From 916c1248e3948d76babb60b5ea0b4dc57d03e989 Mon Sep 17 00:00:00 2001 From: Jin Yi Date: Wed, 21 Jan 2026 06:10:31 +0900 Subject: [PATCH 01/80] [bugfix] Fix search bar height alignment in MediaAssetFilterBar (#8171) --- .../assets/components/MediaAssetFilterBar.vue | 48 +++++++------------ 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/src/platform/assets/components/MediaAssetFilterBar.vue b/src/platform/assets/components/MediaAssetFilterBar.vue index 6a0fcdb93..0442f5f56 100644 --- a/src/platform/assets/components/MediaAssetFilterBar.vue +++ b/src/platform/assets/components/MediaAssetFilterBar.vue @@ -1,40 +1,26 @@ From 79d3b2c291c4bfe1170fb100ca0fc4b3b1bfe8f3 Mon Sep 17 00:00:00 2001 From: AustinMroz Date: Tue, 20 Jan 2026 13:31:56 -0800 Subject: [PATCH 02/80] Fix properties context menu (#8188) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A tiny fix for a regression introduced in #7817 that prevented changing a node's properties through the litegraph context menu. image ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8188-Fix-properties-context-menu-2ee6d73d365081ba8844dd3c8d74432d) by [Unito](https://www.unito.io) --- src/lib/litegraph/src/LGraphCanvas.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/litegraph/src/LGraphCanvas.ts b/src/lib/litegraph/src/LGraphCanvas.ts index 30d7a3fd6..40893174f 100644 --- a/src/lib/litegraph/src/LGraphCanvas.ts +++ b/src/lib/litegraph/src/LGraphCanvas.ts @@ -1350,12 +1350,12 @@ export class LGraphCanvas implements CustomEventDispatcher }) function inner_clicked( - this: ContextMenu, + this: ContextMenuDivElement, v?: string | IContextMenuValue ) { if (!node || typeof v === 'string' || !v?.value) return - const rect = this.root.getBoundingClientRect() + const rect = this.getBoundingClientRect() canvas.showEditPropertyValue(node, v.value, { position: [rect.left, rect.top] }) From 5df793b721c02ef93e7278b4d7bbbcf26ccc11fc Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Tue, 20 Jan 2026 13:35:54 -0800 Subject: [PATCH 03/80] feat: add feature usage tracker for nightly surveys (#8175) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces `useFeatureUsageTracker` composable that tracks how many times a user has used a specific feature, along with first and last usage timestamps. Data persists to localStorage using `@vueuse/core`'s `useStorage`. This composable provides the foundation for triggering surveys after a configurable number of feature uses. Includes comprehensive unit tests. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8175-feat-add-feature-usage-tracker-for-nightly-surveys-2ee6d73d36508118859ece6fcf17561d) by [Unito](https://www.unito.io) --- .../surveys/useFeatureUsageTracker.test.ts | 131 ++++++++++++++++++ .../surveys/useFeatureUsageTracker.ts | 46 ++++++ 2 files changed, 177 insertions(+) create mode 100644 src/platform/surveys/useFeatureUsageTracker.test.ts create mode 100644 src/platform/surveys/useFeatureUsageTracker.ts diff --git a/src/platform/surveys/useFeatureUsageTracker.test.ts b/src/platform/surveys/useFeatureUsageTracker.test.ts new file mode 100644 index 000000000..5313e9eaf --- /dev/null +++ b/src/platform/surveys/useFeatureUsageTracker.test.ts @@ -0,0 +1,131 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' + +const STORAGE_KEY = 'Comfy.FeatureUsage' + +describe('useFeatureUsageTracker', () => { + beforeEach(() => { + localStorage.clear() + vi.resetModules() + }) + + afterEach(() => { + localStorage.clear() + }) + + it('initializes with zero count for new feature', async () => { + const { useFeatureUsageTracker } = await import('./useFeatureUsageTracker') + const { useCount } = useFeatureUsageTracker('test-feature') + + expect(useCount.value).toBe(0) + }) + + it('increments count on trackUsage', async () => { + const { useFeatureUsageTracker } = await import('./useFeatureUsageTracker') + const { useCount, trackUsage } = useFeatureUsageTracker('test-feature') + + expect(useCount.value).toBe(0) + + trackUsage() + expect(useCount.value).toBe(1) + + trackUsage() + expect(useCount.value).toBe(2) + }) + + it('sets firstUsed only on first use', async () => { + vi.useFakeTimers() + const firstTs = 1000000 + vi.setSystemTime(firstTs) + try { + const { useFeatureUsageTracker } = + await import('./useFeatureUsageTracker') + const { usage, trackUsage } = useFeatureUsageTracker('test-feature') + + trackUsage() + expect(usage.value?.firstUsed).toBe(firstTs) + + vi.setSystemTime(firstTs + 5000) + trackUsage() + expect(usage.value?.firstUsed).toBe(firstTs) + } finally { + vi.useRealTimers() + } + }) + + it('updates lastUsed on each use', async () => { + vi.useFakeTimers() + try { + const { useFeatureUsageTracker } = + await import('./useFeatureUsageTracker') + const { usage, trackUsage } = useFeatureUsageTracker('test-feature') + + trackUsage() + const firstLastUsed = usage.value?.lastUsed ?? 0 + + vi.advanceTimersByTime(10) + trackUsage() + + expect(usage.value?.lastUsed).toBeGreaterThan(firstLastUsed) + } finally { + vi.useRealTimers() + } + }) + + it('reset clears feature data', async () => { + const { useFeatureUsageTracker } = await import('./useFeatureUsageTracker') + const { useCount, trackUsage, reset } = + useFeatureUsageTracker('test-feature') + + trackUsage() + trackUsage() + expect(useCount.value).toBe(2) + + reset() + expect(useCount.value).toBe(0) + }) + + it('tracks multiple features independently', async () => { + const { useFeatureUsageTracker } = await import('./useFeatureUsageTracker') + const featureA = useFeatureUsageTracker('feature-a') + const featureB = useFeatureUsageTracker('feature-b') + + featureA.trackUsage() + featureA.trackUsage() + featureB.trackUsage() + + expect(featureA.useCount.value).toBe(2) + expect(featureB.useCount.value).toBe(1) + }) + + it('persists to localStorage', async () => { + vi.useFakeTimers() + try { + const { useFeatureUsageTracker } = + await import('./useFeatureUsageTracker') + const { trackUsage } = useFeatureUsageTracker('persisted-feature') + + trackUsage() + await vi.runAllTimersAsync() + + const stored = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '{}') + expect(stored['persisted-feature']?.useCount).toBe(1) + } finally { + vi.useRealTimers() + } + }) + + it('loads existing data from localStorage', async () => { + localStorage.setItem( + STORAGE_KEY, + JSON.stringify({ + 'existing-feature': { useCount: 5, firstUsed: 1000, lastUsed: 2000 } + }) + ) + + vi.resetModules() + const { useFeatureUsageTracker } = await import('./useFeatureUsageTracker') + const { useCount } = useFeatureUsageTracker('existing-feature') + + expect(useCount.value).toBe(5) + }) +}) diff --git a/src/platform/surveys/useFeatureUsageTracker.ts b/src/platform/surveys/useFeatureUsageTracker.ts new file mode 100644 index 000000000..b8d825db4 --- /dev/null +++ b/src/platform/surveys/useFeatureUsageTracker.ts @@ -0,0 +1,46 @@ +import { useStorage } from '@vueuse/core' +import { computed } from 'vue' + +interface FeatureUsage { + useCount: number + firstUsed: number + lastUsed: number +} + +type FeatureUsageRecord = Record + +const STORAGE_KEY = 'Comfy.FeatureUsage' + +/** + * Tracks feature usage for survey eligibility. + * Persists to localStorage. + */ +export function useFeatureUsageTracker(featureId: string) { + const usageData = useStorage(STORAGE_KEY, {}) + + const usage = computed(() => usageData.value[featureId]) + + const useCount = computed(() => usage.value?.useCount ?? 0) + + function trackUsage() { + const now = Date.now() + const existing = usageData.value[featureId] + + usageData.value[featureId] = { + useCount: (existing?.useCount ?? 0) + 1, + firstUsed: existing?.firstUsed ?? now, + lastUsed: now + } + } + + function reset() { + delete usageData.value[featureId] + } + + return { + usage, + useCount, + trackUsage, + reset + } +} From e8b45204f2922fe46d2b25c0f0b0894f13e926a8 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Tue, 20 Jan 2026 14:22:25 -0800 Subject: [PATCH 04/80] feat(panel): add collapsible Advanced Inputs section for widgets marked advanced (#8146) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a collapsible 'Advanced Inputs' section to the right-side panel that displays widgets marked with `options.advanced = true`. image ## Changes - Filters normal widgets to exclude advanced ones - Adds new `advancedWidgetsSectionDataList` computed for advanced widgets - Renders a collapsible section (collapsed by default) for advanced widgets ## Related - Backend PR that adds `advanced` flag: comfyanonymous/ComfyUI#11939 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8146-feat-panel-add-collapsible-Advanced-Inputs-section-for-widgets-marked-advanced-2ec6d73d36508120af1af27110a6fb96) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action Co-authored-by: Rizumu Ayaka --- .../parameters/TabNormalInputs.vue | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/components/rightSidePanel/parameters/TabNormalInputs.vue b/src/components/rightSidePanel/parameters/TabNormalInputs.vue index 30689f1a4..add128876 100644 --- a/src/components/rightSidePanel/parameters/TabNormalInputs.vue +++ b/src/components/rightSidePanel/parameters/TabNormalInputs.vue @@ -25,13 +25,31 @@ const widgetsSectionDataList = computed((): NodeWidgetsListList => { return nodes.map((node) => { const { widgets = [] } = node const shownWidgets = widgets - .filter((w) => !(w.options?.canvasOnly || w.options?.hidden)) + .filter( + (w) => + !(w.options?.canvasOnly || w.options?.hidden || w.options?.advanced) + ) .map((widget) => ({ node, widget })) return { widgets: shownWidgets, node } }) }) +const advancedWidgetsSectionDataList = computed((): NodeWidgetsListList => { + return nodes + .map((node) => { + const { widgets = [] } = node + const advancedWidgets = widgets + .filter( + (w) => + !(w.options?.canvasOnly || w.options?.hidden) && w.options?.advanced + ) + .map((widget) => ({ node, widget })) + return { widgets: advancedWidgets, node } + }) + .filter(({ widgets }) => widgets.length > 0) +}) + const isMultipleNodesSelected = computed( () => widgetsSectionDataList.value.length > 1 ) @@ -56,6 +74,12 @@ const label = computed(() => { : t('rightSidePanel.inputsNone') : undefined // SectionWidgets display node titles by default }) + +const advancedLabel = computed(() => { + return !mustShowNodeTitle && !isMultipleNodesSelected.value + ? t('rightSidePanel.advancedInputs') + : undefined // SectionWidgets display node titles by default +}) From f5a784e5619dda3e81ca1771650a3edf1e1520c3 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Tue, 20 Jan 2026 15:52:40 -0800 Subject: [PATCH 05/80] fix: add plurilization to node pack count in custom node manager dialog (#8191) --- src/locales/en/main.json | 1 + .../manager/packCard/PackCard.test.ts | 25 ++++++++++++++++--- .../components/manager/packCard/PackCard.vue | 9 ++++--- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/locales/en/main.json b/src/locales/en/main.json index fa557ee96..e87121414 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -158,6 +158,7 @@ "choose_file_to_upload": "choose file to upload", "capture": "capture", "nodes": "Nodes", + "nodesCount": "{count} nodes | {count} node | {count} nodes", "community": "Community", "all": "All", "versionMismatchWarning": "Version Compatibility Warning", diff --git a/src/workbench/extensions/manager/components/manager/packCard/PackCard.test.ts b/src/workbench/extensions/manager/components/manager/packCard/PackCard.test.ts index 3e5116739..b3a92e5a3 100644 --- a/src/workbench/extensions/manager/components/manager/packCard/PackCard.test.ts +++ b/src/workbench/extensions/manager/components/manager/packCard/PackCard.test.ts @@ -10,15 +10,22 @@ import type { RegistryPack } from '@/workbench/extensions/manager/types/comfyManagerTypes' +const translateMock = vi.hoisted(() => + vi.fn((key: string, choice?: number) => + typeof choice === 'number' ? `${key}-${choice}` : key + ) +) +const dateMock = vi.hoisted(() => vi.fn(() => '2024. 1. 1.')) + // Mock dependencies vi.mock('vue-i18n', () => ({ useI18n: vi.fn(() => ({ - d: vi.fn(() => '2024. 1. 1.'), - t: vi.fn((key: string) => key) + d: dateMock, + t: translateMock })), createI18n: vi.fn(() => ({ global: { - t: vi.fn((key: string) => key), + t: translateMock, te: vi.fn(() => true) } })) @@ -187,6 +194,18 @@ describe('PackCard', () => { // Should still render without errors expect(wrapper.exists()).toBe(true) }) + + it('should use localized singular/plural nodes label', () => { + const packWithNodes = { + ...mockNodePack, + comfy_nodes: ['node-a'] + } as MergedNodePack + + const wrapper = createWrapper({ nodePack: packWithNodes }) + + expect(wrapper.text()).toContain('g.nodesCount-1') + expect(translateMock).toHaveBeenCalledWith('g.nodesCount', 1) + }) }) describe('component structure', () => { diff --git a/src/workbench/extensions/manager/components/manager/packCard/PackCard.vue b/src/workbench/extensions/manager/components/manager/packCard/PackCard.vue index 6900e71df..17ffdd102 100644 --- a/src/workbench/extensions/manager/components/manager/packCard/PackCard.vue +++ b/src/workbench/extensions/manager/components/manager/packCard/PackCard.vue @@ -36,8 +36,8 @@

-
- {{ nodesCount }} {{ $t('g.nodes') }} +
+ {{ nodesLabel }}
() -const { d } = useI18n() +const { d, t } = useI18n() const colorPaletteStore = useColorPaletteStore() const isLightTheme = computed( @@ -115,6 +115,9 @@ const isDisabled = computed( const nodesCount = computed(() => isMergedNodePack(nodePack) ? nodePack.comfy_nodes?.length : undefined ) +const nodesLabel = computed(() => + nodesCount.value ? t('g.nodesCount', nodesCount.value) : '' +) const publisherName = computed(() => { if (!nodePack) return null From e6ef99e92ca446bbd869190e725ae2f219ce1a88 Mon Sep 17 00:00:00 2001 From: Simula_r <18093452+simula-r@users.noreply.github.com> Date: Tue, 20 Jan 2026 16:13:54 -0800 Subject: [PATCH 06/80] feat: add isCloud guard to team workspaces feature flag (#8192) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensures the team_workspaces_enabled feature flag only returns true when running in cloud environment, preventing the feature from activating in local/desktop installations. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8192-feat-add-isCloud-guard-to-team-workspaces-feature-flag-2ee6d73d3650810bb1d7c1721ebcdd44) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude Opus 4.5 Co-authored-by: GitHub Action --- src/composables/useFeatureFlags.ts | 3 +++ .../assets/components/MediaAssetFilterBar.vue | 26 +++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/composables/useFeatureFlags.ts b/src/composables/useFeatureFlags.ts index 136b7ccd1..ca54bb9c6 100644 --- a/src/composables/useFeatureFlags.ts +++ b/src/composables/useFeatureFlags.ts @@ -1,5 +1,6 @@ import { computed, reactive, readonly } from 'vue' +import { isCloud } from '@/platform/distribution/types' import { remoteConfig } from '@/platform/remoteConfig/remoteConfig' import { api } from '@/scripts/api' @@ -95,6 +96,8 @@ export function useFeatureFlags() { ) }, get teamWorkspacesEnabled() { + if (!isCloud) return false + return ( remoteConfig.value.team_workspaces_enabled ?? api.getServerFeature(ServerFeatureFlag.TEAM_WORKSPACES_ENABLED, false) diff --git a/src/platform/assets/components/MediaAssetFilterBar.vue b/src/platform/assets/components/MediaAssetFilterBar.vue index 0442f5f56..6e4ec5e4c 100644 --- a/src/platform/assets/components/MediaAssetFilterBar.vue +++ b/src/platform/assets/components/MediaAssetFilterBar.vue @@ -6,20 +6,36 @@ @update:model-value="handleSearchChange" />
- + - + - +
From b1dfbfaa09cd5f76ca8c11715a913283dfd4b3c3 Mon Sep 17 00:00:00 2001 From: Alexander Brown Date: Tue, 20 Jan 2026 16:44:08 -0800 Subject: [PATCH 07/80] chore: Replace prettier with oxfmt (#8177) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Configure oxfmt ignorePatterns to exclude non-JS/TS files (md, json, css, yaml, etc.) to match previous Prettier behavior. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8177-chore-configure-oxfmt-to-format-only-JS-TS-Vue-files-2ee6d73d3650815080f3cc8a4a932109) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp --- .claude/commands/setup_repo.md | 2 +- .github/workflows/ci-lint-format.yaml | 6 +- .i18nrc.cjs | 18 +- .oxfmtrc.json | 20 ++ .prettierignore | 2 - .prettierrc | 11 - .vscode/extensions.json | 15 +- AGENTS.md | 8 +- eslint.config.ts | 6 +- lint-staged.config.mjs | 25 -- lint-staged.config.ts | 5 +- package.json | 10 +- pnpm-lock.yaml | 323 ++++++------------- pnpm-workspace.yaml | 4 +- src/composables/useContextMenuTranslation.ts | 3 +- vite.config.mts | 3 +- 16 files changed, 158 insertions(+), 303 deletions(-) create mode 100644 .oxfmtrc.json delete mode 100644 .prettierignore delete mode 100644 .prettierrc delete mode 100644 lint-staged.config.mjs diff --git a/.claude/commands/setup_repo.md b/.claude/commands/setup_repo.md index d82e22ec6..71dee96a5 100644 --- a/.claude/commands/setup_repo.md +++ b/.claude/commands/setup_repo.md @@ -122,7 +122,7 @@ echo " pnpm build - Build for production" echo " pnpm test:unit - Run unit tests" echo " pnpm typecheck - Run TypeScript checks" echo " pnpm lint - Run ESLint" -echo " pnpm format - Format code with Prettier" +echo " pnpm format - Format code with oxfmt" echo "" echo "Next steps:" echo "1. Run 'pnpm dev' to start developing" diff --git a/.github/workflows/ci-lint-format.yaml b/.github/workflows/ci-lint-format.yaml index 3ce6d6aa9..c97f6255c 100644 --- a/.github/workflows/ci-lint-format.yaml +++ b/.github/workflows/ci-lint-format.yaml @@ -42,7 +42,7 @@ jobs: - name: Run Stylelint with auto-fix run: pnpm stylelint:fix - - name: Run Prettier with auto-format + - name: Run oxfmt with auto-format run: pnpm format - name: Check for changes @@ -60,7 +60,7 @@ jobs: git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git add . - git commit -m "[automated] Apply ESLint and Prettier fixes" + git commit -m "[automated] Apply ESLint and Oxfmt fixes" git push - name: Final validation @@ -80,7 +80,7 @@ jobs: issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: '## 🔧 Auto-fixes Applied\n\nThis PR has been automatically updated to fix linting and formatting issues.\n\n**⚠️ Important**: Your local branch is now behind. Run `git pull` before making additional changes to avoid conflicts.\n\n### Changes made:\n- ESLint auto-fixes\n- Prettier formatting' + body: '## 🔧 Auto-fixes Applied\n\nThis PR has been automatically updated to fix linting and formatting issues.\n\n**⚠️ Important**: Your local branch is now behind. Run `git pull` before making additional changes to avoid conflicts.\n\n### Changes made:\n- ESLint auto-fixes\n- Oxfmt formatting' }) - name: Comment on PR about manual fix needed diff --git a/.i18nrc.cjs b/.i18nrc.cjs index 86ce06eaa..4369f0a70 100644 --- a/.i18nrc.cjs +++ b/.i18nrc.cjs @@ -1,7 +1,7 @@ // This file is intentionally kept in CommonJS format (.cjs) // to resolve compatibility issues with dependencies that require CommonJS. // Do not convert this file to ESModule format unless all dependencies support it. -const { defineConfig } = require('@lobehub/i18n-cli'); +const { defineConfig } = require('@lobehub/i18n-cli') module.exports = defineConfig({ modelName: 'gpt-4.1', @@ -10,7 +10,19 @@ module.exports = defineConfig({ entry: 'src/locales/en', entryLocale: 'en', output: 'src/locales', - outputLocales: ['zh', 'zh-TW', 'ru', 'ja', 'ko', 'fr', 'es', 'ar', 'tr', 'pt-BR', 'fa'], + outputLocales: [ + 'zh', + 'zh-TW', + 'ru', + 'ja', + 'ko', + 'fr', + 'es', + 'ar', + 'tr', + 'pt-BR', + 'fa' + ], reference: `Special names to keep untranslated: flux, photomaker, clip, vae, cfg, stable audio, stable cascade, stable zero, controlnet, lora, HiDream, Civitai, Hugging Face. 'latent' is the short form of 'latent space'. 'mask' is in the context of image processing. @@ -26,4 +38,4 @@ module.exports = defineConfig({ - Use Arabic-Indic numerals (۰-۹) for numbers where appropriate. - Maintain consistency with terminology used in Persian software and design applications. ` -}); +}) diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 000000000..5da4febe2 --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,20 @@ +{ + "$schema": "./node_modules/oxfmt/configuration_schema.json", + "singleQuote": true, + "tabWidth": 2, + "semi": false, + "trailingComma": "none", + "printWidth": 80, + "ignorePatterns": [ + "packages/registry-types/src/comfyRegistryTypes.ts", + "src/types/generatedManagerTypes.ts", + "**/*.md", + "**/*.json", + "**/*.css", + "**/*.yaml", + "**/*.yml", + "**/*.html", + "**/*.svg", + "**/*.xml" + ] +} diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 4403edd8e..000000000 --- a/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -packages/registry-types/src/comfyRegistryTypes.ts -src/types/generatedManagerTypes.ts diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index aa43a43ac..000000000 --- a/.prettierrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "singleQuote": true, - "tabWidth": 2, - "semi": false, - "trailingComma": "none", - "printWidth": 80, - "importOrder": ["^@core/(.*)$", "", "^@/(.*)$", "^[./]"], - "importOrderSeparation": true, - "importOrderSortSpecifiers": true, - "plugins": ["@prettier/plugin-oxc", "@trivago/prettier-plugin-sort-imports"] -} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 54f28d400..9cbac42d7 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,25 +1,22 @@ { "recommendations": [ + "antfu.vite", "austenc.tailwind-docs", "bradlc.vscode-tailwindcss", "davidanson.vscode-markdownlint", "dbaeumer.vscode-eslint", + "donjayamanne.githistory", "eamodio.gitlens", - "esbenp.prettier-vscode", - "figma.figma-vscode-extension", "github.vscode-github-actions", "github.vscode-pull-request-github", "hbenl.vscode-test-explorer", + "kisstkondoros.vscode-codemetrics", "lokalise.i18n-ally", "ms-playwright.playwright", + "oxc.oxc-vscode", + "sonarsource.sonarlint-vscode", "vitest.explorer", "vue.volar", - "sonarsource.sonarlint-vscode", - "deque-systems.vscode-axe-linter", - "kisstkondoros.vscode-codemetrics", - "donjayamanne.githistory", - "wix.vscode-import-cost", - "prograhammer.tslint-vue", - "antfu.vite" + "wix.vscode-import-cost" ] } diff --git a/AGENTS.md b/AGENTS.md index da2953783..9938865a9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -27,10 +27,10 @@ See @docs/guidance/*.md for file-type-specific conventions (auto-loaded by glob) - Build output: `dist/` - Configs - `vite.config.mts` - - `vitest.config.ts` - `playwright.config.ts` - `eslint.config.ts` - - `.prettierrc` + - `.oxfmtrc.json` + - `.oxlintrc.json` - etc. ## Monorepo Architecture @@ -46,7 +46,7 @@ The project uses **Nx** for build orchestration and task management - `pnpm test:unit`: Run Vitest unit tests - `pnpm test:browser`: Run Playwright E2E tests (`browser_tests/`) - `pnpm lint` / `pnpm lint:fix`: Lint (ESLint) -- `pnpm format` / `pnpm format:check`: Prettier +- `pnpm format` / `pnpm format:check`: oxfmt - `pnpm typecheck`: Vue TSC type checking - `pnpm storybook`: Start Storybook development server @@ -72,7 +72,7 @@ The project uses **Nx** for build orchestration and task management - Composition API only - Tailwind 4 styling - Avoid ` diff --git a/src/components/sidebar/SidebarIcon.test.ts b/src/components/sidebar/SidebarIcon.test.ts index 7564e7bcd..284a29825 100644 --- a/src/components/sidebar/SidebarIcon.test.ts +++ b/src/components/sidebar/SidebarIcon.test.ts @@ -1,6 +1,5 @@ import { mount } from '@vue/test-utils' import PrimeVue from 'primevue/config' -import OverlayBadge from 'primevue/overlaybadge' import Tooltip from 'primevue/tooltip' import { describe, expect, it } from 'vitest' import { createI18n } from 'vue-i18n' @@ -33,8 +32,7 @@ describe('SidebarIcon', () => { return mount(SidebarIcon, { global: { plugins: [PrimeVue, i18n], - directives: { tooltip: Tooltip }, - components: { OverlayBadge } + directives: { tooltip: Tooltip } }, props: { ...exampleProps, ...props }, ...options @@ -54,9 +52,9 @@ describe('SidebarIcon', () => { it('creates badge when iconBadge prop is set', () => { const badge = '2' const wrapper = mountSidebarIcon({ iconBadge: badge }) - const badgeEl = wrapper.findComponent(OverlayBadge) + const badgeEl = wrapper.find('.sidebar-icon-badge') expect(badgeEl.exists()).toBe(true) - expect(badgeEl.find('.p-badge').text()).toEqual(badge) + expect(badgeEl.text()).toEqual(badge) }) it('shows tooltip on hover', async () => { diff --git a/src/components/sidebar/SidebarIcon.vue b/src/components/sidebar/SidebarIcon.vue index 88900c1a7..10dfca8f8 100644 --- a/src/components/sidebar/SidebarIcon.vue +++ b/src/components/sidebar/SidebarIcon.vue @@ -17,22 +17,28 @@ >