Skip to content

chore: upgrade frontend dependencies - #836

Open
Colin-XKL wants to merge 4 commits into
devfrom
cursor/upgrade-frontend-deps-2f5b
Open

chore: upgrade frontend dependencies#836
Colin-XKL wants to merge 4 commits into
devfrom
cursor/upgrade-frontend-deps-2f5b

Conversation

@Colin-XKL

@Colin-XKL Colin-XKL commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Summary

  • Upgrade the admin frontend direct dependencies and lockfile to the latest available versions.
  • Migrate ESLint to flat config, Tailwind 4 PostCSS integration, Vite 8 manual chunk config, and related TypeScript/Vue/Arco compatibility fixes.
  • Correct the Tailwind v4 import/config ordering so utility CSS is emitted; this restores the content-area and card spacing (px-16 / py-8) to match main.
  • Restore visible login-page branding by using the theme foreground color on the single-column white layout and removing obsolete Banner CSS.
  • Add Vitest alias config for the existing frontend tests.

Validation

  • pnpm outdated --format table
  • pnpm run lint
  • pnpm run type:check
  • pnpm run build
  • pnpm run test
  • task frontend-build
  • Browser comparison at 100% zoom against main for AtomCraft and HTML to RSS.

Manual walkthrough

main_upgrade_padding_comparison.mp4

To show artifacts inline, enable in settings.

Open in Web Open in Cursor 

Summary by Sourcery

Upgrade the admin frontend stack to current Vue, Vite, Tailwind, ESLint, and related tooling versions while applying necessary compatibility updates across the codebase.

Enhancements:

  • Bump core runtime dependencies (Vue, vue-router, vue-i18n, Pinia, Axios, VueUse, ECharts, Arco, and utilities) and dev tooling (Vite, Vitest, TypeScript, Rollup, Tailwind, ESLint, Prettier, and related plugins) to newer versions.
  • Adjust Vue components, props typing, and event handlers to align with updated Vue, Arco, and TypeScript behaviors, including stricter typing and safer number handling in form inputs.
  • Refine various dashboard forms and validators for better type safety and alignment with updated component APIs, including explicit form models and button style tweaks.
  • Update Vite production build chunking to use a function-based manualChunks configuration compatible with Vite 8 and Rollup 4.
  • Migrate PostCSS/Tailwind integration to use the new @tailwindcss/postcss plugin and refresh PostCSS configuration.
  • Simplify TypeScript and Vue type declarations (tsconfig, env/component typings) for improved editor support and compatibility with newer tooling.

Build:

  • Introduce a flat ESLint configuration file and remove legacy .eslintrc, Babel config, and Vite ESLint plugin wiring.
  • Update Vitest configuration to define the src alias for tests and align with the upgraded tooling.
  • Refresh pnpm lockfile to reflect upgraded dependencies and tooling versions.

Tests:

  • Add a dedicated Vitest config with path alias resolution to support existing frontend tests.

Chores:

  • Remove obsolete ESLint ignore and Babel config files that are no longer needed with the new tooling setup.

Co-authored-by: Colin <Colin_XKL@outlook.com>
@vercel

vercel Bot commented Jun 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
feed-craft-admin Ready Ready Preview, Comment Jul 28, 2026 11:52am
feed-craft-doc Ready Ready Preview, Comment Jul 28, 2026 11:52am

@sourcery-ai

sourcery-ai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Upgrade admin frontend dependencies and tooling (Vue, Vite, Tailwind, ESLint, Vitest, TypeScript) and adjust app code and config for new versions, including stricter typing, updated Arco behaviors, manual Rollup chunks, and test aliases.

Sequence diagram for updated numeric param handling in craft_atom.vue

sequenceDiagram
  actor User
  participant AInputNumber as AInputNumber
  participant CraftAtom as CraftAtomComponent

  User->>AInputNumber: change value in UI
  AInputNumber->>CraftAtom: update:model-value(value)
  CraftAtom->>CraftAtom: updateNumberParamValue(param, value)
  CraftAtom->>CraftAtom: param.value = value ?? ''

  note over AInputNumber,CraftAtom: Initial render
  CraftAtom->>CraftAtom: toNumberParamValue(param.value)
  CraftAtom-->>AInputNumber: model-value (number | undefined)
Loading

File-Level Changes

Change Details Files
Upgrade runtime and dev dependencies for the admin frontend to the latest Vue/Vite/Tailwind/Arco/TypeScript ecosystem versions and refresh the lockfile.
  • Bump core runtime dependencies such as Vue 3.5, Vue Router 5, Pinia 3, vue-i18n 11, axios 1.x, vue-echarts 8, echarts 6 and related libraries.
  • Bump dev tooling dependencies including Vite 8, vitest 4, rollup 4, TailwindCSS 4, TypeScript 6, unplugin-vue-components 32, ESLint 10, @typescript-eslint 8, and others.
  • Remove the explicit rollup 2 resolution override and rely on the updated Rollup 4 dependency.
  • Regenerate pnpm-lock.yaml to reflect the upgraded dependencies.
web/admin/package.json
web/admin/pnpm-lock.yaml
Migrate ESLint to the flat config format and align linting with modern Vue/TypeScript and Prettier integration.
  • Introduce eslint.config.mjs using @eslint/js, eslint-plugin-vue flat config, @typescript-eslint, eslint-plugin-prettier and globals, with project-specific rules.
  • Set vue-eslint-parser and TypeScript parser as nested parser for .ts and .vue files with JSX support.
  • Remove legacy .eslintrc.js, .eslintignore and babel.config.js in favor of flat config.
  • Relax or customize several Vue and TypeScript lint rules (e.g., default props, multi-word names, no-param-reassign) to match existing codebase behaviors.
web/admin/eslint.config.mjs
web/admin/.eslintrc.js
web/admin/.eslintignore
web/admin/babel.config.js
Update Vite build configuration for Rollup 4/Vite 8 and remove in-bundler ESLint plugin usage.
  • Change production rollupOptions.output.manualChunks from a static object to a function that groups node_modules into logical chunks (arco, chart, vue) based on module path checks.
  • Remove vite-plugin-eslint from the dev Vite config plugins, relying on external lint runs instead.
  • Keep code-inspector-plugin in the dev config unchanged while merging with base config.
web/admin/config/vite.config.prod.ts
web/admin/config/vite.config.dev.ts
Adjust Vue components and forms for updated Arco and Vue behavior, especially around typed props, numeric inputs, and form models.
  • Refactor several components’ props (e.g., CraftSelector, CraftPickerModal) to use defineProps with TypeScript generics and withDefaults instead of runtime prop options, tightening types.
  • Replace v-model on Arco numeric inputs (a-input-number) with explicit :model-value plus @update:model-value handlers and helper functions that coerce between string/number and undefined in craft_atom.vue and TopicAggregatorEditor.vue.
  • Ensure textareas use :model-value and explicit update handlers instead of direct v-model when needed.
  • Add :model bindings to various a-form components (e.g., web_monitor, html_to_rss, embedding_filter_debug) to satisfy Arco form requirements in newer versions.
  • Adjust button type for the feed_viewer primary/secondary action to match updated Arco button type options.
web/admin/src/views/dashboard/craft_flow/CraftSelector.vue
web/admin/src/views/dashboard/craft_flow/components/CraftPickerModal.vue
web/admin/src/views/dashboard/craft_atom/craft_atom.vue
web/admin/src/views/dashboard/topic_feed/components/TopicAggregatorEditor.vue
web/admin/src/views/dashboard/web_monitor/web_monitor.vue
web/admin/src/views/dashboard/html_to_rss/html_to_rss.vue
web/admin/src/views/dashboard/embedding_filter_debug/index.vue
web/admin/src/views/dashboard/feed_viewer/feed_viewer.vue
Improve typing and runtime safety for Arco Tree usage and various event handlers with updated type definitions.
  • Introduce a JsonTreeNodeData type extending Arco TreeNodeData with data/children metadata and use it in jsonToTree to build JSON tree views.
  • Relax handleNodeSelect’s node argument type to optional and guard against missing keys; cast node to JsonTreeNodeData when accessing custom data.
  • Split Arco imports to use type-only import for TreeNodeData to work with TS 6 and Vue 3.5 tooling.
  • Adjust event handlers (e.g., TopicInputSourcesEditor, topic_feed detail switches) to cast or coerce event payloads (Boolean/value) explicitly before passing to handlers.
web/admin/src/views/dashboard/curl_to_rss/curl_to_rss.vue
web/admin/src/views/dashboard/topic_feed/components/TopicInputSourcesEditor.vue
web/admin/src/views/dashboard/topic_feed/detail.vue
Align TypeScript and Vue typing setup with modern bundler expectations and updated Vue tooling.
  • Update tsconfig.json to use module ESNext and moduleResolution Bundler, and adjust base path mapping for '@/…' to './src/*'.
  • Add vueCompilerOptions.strictTemplates=false to relax template type checking with newer Vue tooling.
  • Refine env.d.ts’s DefineComponent type to use empty object records for props/data and keep any for the rest.
  • Update components.d.ts to import GlobalComponents from 'vue', declare RouterLink/RouterView in the vue module, and add global constants for TSX support, also annotating lint suppression comments for new linters.
  • Use updated axios types (InternalAxiosRequestConfig) and simplify request interceptor header initialization in interceptor.ts.
web/admin/tsconfig.json
web/admin/src/env.d.ts
web/admin/components.d.ts
web/admin/src/api/interceptor.ts
Modernize PostCSS/Tailwind and validators and add Vitest configuration with path aliases.
  • Switch PostCSS config to use the Tailwind 4 '@tailwindcss/postcss' plugin instead of the tailwindcss plugin key.
  • Slightly simplify utils/validator.ts by removing the obsolete eslint import/prefer-default-export suppression comment.
  • Introduce vitest.config.ts that defines a resolve.alias mapping '@' to the src directory, enabling tests to use existing path aliases.
web/admin/postcss.config.js
web/admin/src/utils/validator.ts
web/admin/vitest.config.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request upgrades various dependencies (including Vue, Vite, ESLint, and TailwindCSS), migrates to the ESLint flat configuration format, and refactors several Vue components to use TypeScript-based props. The feedback highlights several important issues: the manualChunks configuration in Vite should be updated to correctly group Vue and VueUse core packages; the Node.js engine requirement in package.json needs to be bumped to support the upgraded build tools; and the number-parsing helper functions in craft_atom.vue and TopicAggregatorEditor.vue should explicitly handle null and empty strings to prevent incorrect coercion to 0.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +30 to +38
if (
id.includes('/vue/') ||
id.includes('/vue-router/') ||
id.includes('/pinia/') ||
id.includes('/@vueuse/core/') ||
id.includes('/vue-i18n/')
) {
return 'vue';
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The manualChunks matching logic for the vue chunk only checks for /vue/ and /@vueuse/core/. This will miss Vue core runtime packages (which are scoped under /@vue/, such as @vue/runtime-core, @vue/shared, @vue/reactivity) and other VueUse packages (like @vueuse/shared). As a result, these core dependencies will not be grouped into the vue chunk, defeating the purpose of the optimization. Consider updating the matching logic to include /@vue/ and /@vueuse/.

Suggested change
if (
id.includes('/vue/') ||
id.includes('/vue-router/') ||
id.includes('/pinia/') ||
id.includes('/@vueuse/core/') ||
id.includes('/vue-i18n/')
) {
return 'vue';
}
if (
id.includes('/vue/') ||
id.includes('/@vue/') ||
id.includes('/vue-router/') ||
id.includes('/pinia/') ||
id.includes('/@vueuse/') ||
id.includes('/vue-i18n/')
) {
return 'vue';
}

Comment thread web/admin/package.json
Comment on lines 97 to 99
"engines": {
"node": ">=14.0.0"
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Node.js engine requirement is still set to >=14.0.0. However, the upgraded dependencies (such as ESLint v10 and Vite v8) require much newer Node.js versions (ESLint v10 requires >=18.18.0 or >=20.0.0, and Vite v8/v6 requires >=18.0.0). Keeping the engine requirement at >=14.0.0 will cause installation or runtime failures on older Node.js environments. Please update the engine requirement to a compatible version.

Suggested change
"engines": {
"node": ">=14.0.0"
},
"engines": {
"node": ">=18.18.0"
},

Comment on lines +369 to +374
const toNumberParamValue = (value: CraftParamValue) => {
if (typeof value === 'number') return value;
if (value === '') return undefined;
const parsed = Number(value);
return Number.isNaN(parsed) ? undefined : parsed;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In JavaScript, Number(null) evaluates to 0 and Number('') evaluates to 0. While empty string is explicitly handled, null or undefined values are not. If value is null (e.g., from an API response or cleared state), toNumberParamValue will return 0 instead of undefined, causing the input field to display 0 instead of remaining empty. Consider explicitly checking for null and undefined.

  const toNumberParamValue = (value: CraftParamValue) => {
    if (value === null || value === undefined || value === '') return undefined;
    if (typeof value === 'number') return value;
    const parsed = Number(value);
    return Number.isNaN(parsed) ? undefined : parsed;
  };

Comment on lines +175 to +179
const toNumberValue = (value: string | number) => {
if (typeof value === 'number') return value;
const parsed = Number(value);
return Number.isNaN(parsed) ? undefined : parsed;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In JavaScript, Number('') evaluates to 0. If value is an empty string '' (e.g., when the input is cleared), toNumberValue will return 0 instead of undefined, causing the input field to display 0 instead of remaining empty. Consider explicitly checking for empty string, null, and undefined.

  const toNumberValue = (value: string | number | undefined | null) => {
    if (value === null || value === undefined || value === '') return undefined;
    if (typeof value === 'number') return value;
    const parsed = Number(value);
    return Number.isNaN(parsed) ? undefined : parsed;
  };

@codacy-production

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 1 medium

Alerts:
⚠ 1 issue (≤ 0 issues of at least medium severity)

Results:
1 new issue

Category Results
Complexity 1 medium

View in Codacy

🟢 Metrics 18 complexity

Metric Results
Complexity 18

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

chore(admin): upgrade frontend deps and migrate lint/build configs

⚙️ Configuration changes ✨ Enhancement 🕐 40+ Minutes

Grey Divider

AI Description

• Upgrade admin frontend dependencies to current Vue/Vite/Tailwind/ESLint/Vitest versions.
• Migrate ESLint to flat config and adjust Vite chunking + Tailwind 4 PostCSS integration.
• Fix TS/Vue/Arco typing and v-model bindings to match updated library behavior.
Diagram

graph TD
  pkg["package.json"] --> vite["Vite configs"] --> ui["Vue views/components"]
  pkg --> eslint["ESLint flat config"] --> ui
  pkg --> postcss["PostCSS/Tailwind"] --> ui
  pkg --> vitest["Vitest config"] --> ui
  pkg --> ts["tsconfig.json"] --> ui
  ui --> api["Axios interceptor"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Keep legacy ESLint config via FlatCompat
  • ➕ Less rewrite risk; preserves existing rule inheritance/behavior
  • ➕ Easier to diff/compare old vs new config during the upgrade
  • ➖ Carries compatibility glue and technical debt
  • ➖ Often blocks taking full advantage of ESLint v10 flat config ecosystem
2. Use Vite splitVendorChunkPlugin instead of custom manualChunks
  • ➕ Less bespoke chunking logic to maintain across Vite/Rollup upgrades
  • ➕ Commonly recommended default; fewer edge cases in path matching
  • ➖ Less control over named buckets (arco/chart/vue) if that’s a perf requirement
  • ➖ May change caching characteristics compared to explicit groupings

Recommendation: Current approach is appropriate: a direct upgrade plus targeted compatibility fixes keeps the toolchain modern and removes legacy config files (old .eslintrc/.eslintignore/vite-plugin-eslint). The custom manualChunks function is reasonable if stable vendor chunk naming is desired; otherwise, consider splitVendorChunkPlugin to reduce ongoing maintenance.

Files changed (22) +267 / -137

Bug fix (10) +72 / -26
interceptor.tsUpdate axios interceptor types for axios v1 +2/-5

Update axios interceptor types for axios v1

• Updates request interceptor typing from AxiosRequestConfig to InternalAxiosRequestConfig. Removes defensive header initialization that is no longer needed with the newer typing/behavior.

web/admin/src/api/interceptor.ts

craft_atom.vueFix numeric input bindings for updated Arco/Vue behavior +24/-3

Fix numeric input bindings for updated Arco/Vue behavior

• Replaces v-model on a-input-number with explicit :model-value and @update:model-value to control number/empty handling. Adds helper functions to safely coerce string/empty values to numbers and back.

web/admin/src/views/dashboard/craft_atom/craft_atom.vue

curl_to_rss.vueHarden TreeNode typing and selection handling +17/-8

Harden TreeNode typing and selection handling

• Splits value/type imports for Arco TreeNodeData and introduces a JsonTreeNodeData extension type for custom node metadata. Makes node selection callback resilient to undefined node and updates array-type checks accordingly.

web/admin/src/views/dashboard/curl_to_rss/curl_to_rss.vue

index.vueBind Arco form model explicitly +1/-1

Bind Arco form model explicitly

• Adds :model binding to the form to satisfy updated Arco form expectations and stricter template/type checking.

web/admin/src/views/dashboard/embedding_filter_debug/index.vue

feed_viewer.vueAdjust button type to new Arco variants +1/-1

Adjust button type to new Arco variants

• Changes the non-primary button type from 'default' to 'secondary' to match updated Arco button API/semantics.

web/admin/src/views/dashboard/feed_viewer/feed_viewer.vue

html_to_rss.vueProvide form model for URL step +1/-1

Provide form model for URL step

• Adds an explicit :model object for the step-1 form to satisfy Arco's model-driven form behavior and updated typings.

web/admin/src/views/dashboard/html_to_rss/html_to_rss.vue

TopicAggregatorEditor.vueFix numeric editor v-model and coercion logic +20/-1

Fix numeric editor v-model and coercion logic

• Replaces v-model usage with :model-value and @update:model-value for number input compatibility. Adds helpers to coerce values safely and updates step values immutably via updateSteps.

web/admin/src/views/dashboard/topic_feed/components/TopicAggregatorEditor.vue

TopicInputSourcesEditor.vueNormalize Arco event payload types in handlers +2/-2

Normalize Arco event payload types in handlers

• Updates change handlers to cast/normalize event values (radio group and switch) to expected types, avoiding stricter type errors after dependency upgrades.

web/admin/src/views/dashboard/topic_feed/components/TopicInputSourcesEditor.vue

detail.vueNormalize switch change value for disabled toggle +2/-2

Normalize switch change value for disabled toggle

• Wraps the switch change payload in Boolean() before passing to the toggle handler to handle widened event types from upgraded Arco components.

web/admin/src/views/dashboard/topic_feed/detail.vue

web_monitor.vueAdd explicit form models for URL and preview forms +2/-2

Add explicit form models for URL and preview forms

• Adds :model bindings to forms used in step 1 and step 2 preview to align with updated Arco form requirements and reduce template/type issues.

web/admin/src/views/dashboard/web_monitor/web_monitor.vue

Refactor (3) +28 / -37
validator.tsRemove legacy ESLint suppression comment +0/-1

Remove legacy ESLint suppression comment

• Deletes an 'import/prefer-default-export' disable comment that no longer applies after ESLint config migration.

web/admin/src/utils/validator.ts

CraftSelector.vueConvert props to typed defineProps with defaults +14/-18

Convert props to typed defineProps with defaults

• Replaces runtime props options with defineProps generic typing and withDefaults, improving TS inference with Vue 3.5+ and router v5 types.

web/admin/src/views/dashboard/craft_flow/CraftSelector.vue

CraftPickerModal.vueConvert modal props to typed defineProps with defaults +14/-18

Convert modal props to typed defineProps with defaults

• Migrates props definition to defineProps generic typing wrapped in withDefaults to improve type safety and compatibility with upgraded Vue/TS tooling.

web/admin/src/views/dashboard/craft_flow/components/CraftPickerModal.vue

Other (9) +167 / -74
components.d.tsUpdate Vue global component typings for new toolchain +12/-3

Update Vue global component typings for new toolchain

• Switches module augmentation from '@vue/runtime-core' to 'vue' and adds explicit TSX global declarations. Adds ignore directives for additional linters used in the repo/tooling.

web/admin/components.d.ts

vite.config.dev.tsRemove vite-plugin-eslint from dev build +0/-6

Remove vite-plugin-eslint from dev build

• Drops the Vite ESLint plugin from the dev config, aligning linting with the new standalone ESLint flat-config workflow.

web/admin/config/vite.config.dev.ts

vite.config.prod.tsMigrate Rollup manualChunks to function form +20/-4

Migrate Rollup manualChunks to function form

• Replaces object-based manualChunks with a function-based implementation compatible with newer Rollup/Vite. Preserves chunk grouping for Arco, charting libs, and Vue ecosystem packages.

web/admin/config/vite.config.prod.ts

eslint.config.mjsAdd ESLint v10 flat configuration +62/-0

Add ESLint v10 flat configuration

• Introduces a flat-config ESLint setup combining @eslint/js, vue flat recommended, TypeScript parser/plugin, and Prettier integration. Defines ignores and ports key Vue/TS rule customizations from the legacy config.

web/admin/eslint.config.mjs

package.jsonUpgrade admin frontend runtime and dev dependencies +51/-54

Upgrade admin frontend runtime and dev dependencies

• Bumps core runtime deps (Vue, Router, Pinia, axios, echarts, etc.) and major tooling (Vite 8, Rollup 4, Tailwind 4, ESLint 10, TypeScript 6, Vitest 4). Removes legacy/unused tooling entries (e.g., vite-plugin-eslint, babel jsx plugin) and adds new required packages (e.g., @tailwindcss/postcss, globals, vue-eslint-parser).

web/admin/package.json

postcss.config.jsSwitch Tailwind 4 PostCSS plugin entry +1/-1

Switch Tailwind 4 PostCSS plugin entry

• Updates PostCSS config to use '@tailwindcss/postcss' instead of 'tailwindcss' as the PostCSS plugin key, matching Tailwind 4 integration.

web/admin/postcss.config.js

env.d.tsTighten Vue SFC module typing shape +5/-2

Tighten Vue SFC module typing shape

• Refines the '*.vue' module declaration to use explicit empty-record props/state generics while keeping 'any' for the instance type. Removes legacy ESLint suppression comment in favor of clearer typing.

web/admin/src/env.d.ts

tsconfig.jsonAlign TS config with modern bundler resolution and relax template strictness +6/-4

Align TS config with modern bundler resolution and relax template strictness

• Switches to ESNext modules and Bundler moduleResolution, updates path mapping format, and adds vueCompilerOptions.strictTemplates=false to reduce template type friction with the upgraded stack.

web/admin/tsconfig.json

vitest.config.tsAdd Vitest alias resolution for @ imports +10/-0

Add Vitest alias resolution for @ imports

• Introduces a Vitest config that maps '@' to src/ so existing tests resolve path aliases consistently with Vite/TS.

web/admin/vitest.config.ts

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

Fixed security issues:

  • axios (link)

  • brace-expansion (link)

  • form-data (link)

  • lodash (link)

  • minimatch (link)

  • postcss (link)

  • In CraftSelector.vue and CraftPickerModal.vue, the modelValue prop is typed as string | string[] but the default is () => [], which can lead to a runtime type mismatch when mode === 'single'; consider either making the default '' for single mode or changing the prop type to reflect that arrays are always used internally.

  • The new ESLint flat config applies eslint-config-prettier rules globally; if you intend to only disable formatting-related rules for specific file types (e.g., Vue/TS) you may want to scope the Prettier-related rules to those files to avoid unexpected overrides in other parts of the project.

Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `CraftSelector.vue` and `CraftPickerModal.vue`, the `modelValue` prop is typed as `string | string[]` but the default is `() => []`, which can lead to a runtime type mismatch when `mode === 'single'`; consider either making the default `''` for single mode or changing the prop type to reflect that arrays are always used internally.
- The new ESLint flat config applies `eslint-config-prettier` rules globally; if you intend to only disable formatting-related rules for specific file types (e.g., Vue/TS) you may want to scope the Prettier-related rules to those files to avoid unexpected overrides in other parts of the project.

## Individual Comments

### Comment 1
<location path="web/admin/src/views/dashboard/topic_feed/components/TopicAggregatorEditor.vue" line_range="86-90" />
<code_context>
         <a-input-number
           v-else
-          v-model="step.value"
+          :model-value="toNumberValue(step.value)"
           :min="1"
           mode="button"
           style="flex: 1; min-width: 150px"
+          @update:model-value="(value) => updateStepValue(idx, value)"
         />

</code_context>
<issue_to_address>
**suggestion:** Handle empty-string values explicitly in `toNumberValue` to avoid coercing them to `0` unintentionally.

`Number(value)` converts an empty string to `0`, and `updateStepValue` falls back to `1` when `value` is `undefined`, so clearing the input can yield either `0` or `1` depending on timing. To align behavior with `craft_atom.vue` and keep clearing predictable, consider special-casing empty strings:
```ts
const toNumberValue = (value: string | number) => {
  if (typeof value === 'number') return value;
  if (value === '') return undefined;
  const parsed = Number(value);
  return Number.isNaN(parsed) ? undefined : parsed;
};
```

Suggested implementation:

```
const toNumberValue = (value: string | number | undefined) => {
  if (typeof value === 'number') return value;
  if (value === '') return undefined;

  const parsed = Number(value);
  return Number.isNaN(parsed) ? undefined : parsed;
};

```

I assumed there is an existing `toNumberValue` helper defined similarly to `const toNumberValue = (value: string | number) => Number(value);`. If the signature or implementation differs, you should still:
1. Update `toNumberValue` to:
   - Accept `string | number | undefined`.
   - Return the number directly when given a number.
   - Return `undefined` when given an empty string.
   - Parse other strings via `Number(...)` and return `undefined` if the result is `NaN`.
2. Ensure `updateStepValue(idx, value)` accepts `value: number | undefined` and keeps the existing behavior of falling back to `1` only when `value` is `undefined`, so that clearing the input consistently maps to the same default as in `craft_atom.vue`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +86 to +90
:model-value="toNumberValue(step.value)"
:min="1"
mode="button"
style="flex: 1; min-width: 150px"
@update:model-value="(value) => updateStepValue(idx, value)"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Handle empty-string values explicitly in toNumberValue to avoid coercing them to 0 unintentionally.

Number(value) converts an empty string to 0, and updateStepValue falls back to 1 when value is undefined, so clearing the input can yield either 0 or 1 depending on timing. To align behavior with craft_atom.vue and keep clearing predictable, consider special-casing empty strings:

const toNumberValue = (value: string | number) => {
  if (typeof value === 'number') return value;
  if (value === '') return undefined;
  const parsed = Number(value);
  return Number.isNaN(parsed) ? undefined : parsed;
};

Suggested implementation:

const toNumberValue = (value: string | number | undefined) => {
  if (typeof value === 'number') return value;
  if (value === '') return undefined;

  const parsed = Number(value);
  return Number.isNaN(parsed) ? undefined : parsed;
};

I assumed there is an existing toNumberValue helper defined similarly to const toNumberValue = (value: string | number) => Number(value);. If the signature or implementation differs, you should still:

  1. Update toNumberValue to:
    • Accept string | number | undefined.
    • Return the number directly when given a number.
    • Return undefined when given an empty string.
    • Parse other strings via Number(...) and return undefined if the result is NaN.
  2. Ensure updateStepValue(idx, value) accepts value: number | undefined and keeps the existing behavior of falling back to 1 only when value is undefined, so that clearing the input consistently maps to the same default as in craft_atom.vue.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The admin frontend updates its ESLint, TypeScript, Vite, Tailwind, Vitest, and dependency configuration. Vue typings and props use typed forms, while dashboard inputs, forms, event handlers, Axios typing, JSON tree handling, and presentation styles receive targeted updates.

Changes

Admin frontend modernization

Layer / File(s) Summary
Toolchain and build configuration
web/admin/package.json, web/admin/eslint.config.mjs, web/admin/tsconfig.json, web/admin/vitest.config.ts, web/admin/config/*, web/admin/postcss.config.js, web/admin/src/assets/style/tailwind.css
Dependencies and frontend tooling configuration were upgraded, ESLint flat configuration was added, Tailwind/PostCSS integration changed, Vite plugins and chunking were updated, and Vitest alias resolution was introduced.
Vue typing and component contracts
web/admin/components.d.ts, web/admin/src/env.d.ts, web/admin/src/views/dashboard/craft_flow/*
Global Vue and TSX component declarations were updated, Vue component generics were tightened, and dashboard props were migrated to typed defineProps with defaults.
Typed API and dashboard data flows
web/admin/src/api/interceptor.ts, web/admin/src/views/dashboard/curl_to_rss/curl_to_rss.vue, web/admin/src/views/dashboard/craft_atom/craft_atom.vue, web/admin/src/views/dashboard/topic_feed/components/TopicAggregatorEditor.vue
Axios request typing, JSON tree metadata, node selection guards, and controlled numeric input conversions were updated.
Form bindings and event normalization
web/admin/src/views/dashboard/embedding_filter_debug/index.vue, web/admin/src/views/dashboard/html_to_rss/html_to_rss.vue, web/admin/src/views/dashboard/topic_feed/components/TopicInputSourcesEditor.vue, web/admin/src/views/dashboard/topic_feed/detail.vue, web/admin/src/views/dashboard/web_monitor/web_monitor.vue
Arco forms now declare models, and emitted radio and switch values are normalized before updates.
Dashboard presentation updates
web/admin/src/views/dashboard/feed_viewer/feed_viewer.vue, web/admin/src/views/login/index.vue
The feed viewer action button styling and login page banner and logo text styles were updated.

Possibly related PRs

Poem

A bunny hops through types so neat,
With Vue and Vite in sync complete.
Forms now carry models bright,
Numbers turn to values right.
ESLint guards the garden gate! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: upgrading frontend dependencies.
Description check ✅ Passed The description is directly related to the dependency upgrade and supporting tooling changes.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/upgrade-frontend-deps-2f5b

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 17 rules

Grey Divider


Remediation recommended

1. Bad default modelValue type 🐞 Bug ≡ Correctness
Description
CraftPickerModal defaults mode to 'single' but defaults modelValue to [], so when the
modal opens the single-mode sync path wraps the array into localValue and can produce a nested
array (wrong shape) and incorrect emitted values. The same inconsistent default exists in
CraftSelector, so omitting modelValue can pass a non-string into the single-selector path.
Code

web/admin/src/views/dashboard/craft_flow/components/CraftPickerModal.vue[R25-37]

+  const props = withDefaults(
+    defineProps<{
+      visible: boolean;
+      modelValue: string | string[];
+      mode: 'single' | 'multiple';
+      title?: string;
+    }>(),
+    {
+      visible: false,
+      modelValue: () => [],
+      mode: 'single',
+      title: '',
+    }
Relevance

⭐⭐⭐ High

Team previously fixed wrong prop default type (array→object) in PR#311; similar runtime-shape bug
likely accepted.

PR-#311
PR-#304

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The defaults set modelValue to an array while mode defaults to single, and the modal open-sync
logic treats modelValue as a string and wraps it, which can yield a nested array at runtime
because [] is truthy and TS casts do not convert values.

web/admin/src/views/dashboard/craft_flow/components/CraftPickerModal.vue[25-66]
web/admin/src/views/dashboard/craft_flow/CraftSelector.vue[40-53]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`CraftPickerModal` and `CraftSelector` default `mode` to `'single'` but default `modelValue` to an array (`[]`). In single mode, `CraftPickerModal` wraps `props.modelValue` into `localValue` on open, and because `[]` is truthy this can create `localValue` with an invalid nested array shape (and then emit wrong values).

## Issue Context
- `CraftPickerModal` uses a `watch(() => props.visible, ...)` to sync `localValue` when opening; the single-mode branch assumes `props.modelValue` is a string.
- `CraftSelector` also defaults `modelValue` to `[]` while defaulting `mode` to `'single'`, and forwards the value as a string via a cast.

## Fix Focus Areas
- web/admin/src/views/dashboard/craft_flow/components/CraftPickerModal.vue[25-66]
- web/admin/src/views/dashboard/craft_flow/CraftSelector.vue[40-53]

## Suggested fix approach
1. Make `modelValue` default consistent with `mode` default:
  - Either default `modelValue` to `''` (string) when `mode` defaults to `'single'`, or
  - Make `modelValue` optional (default `undefined`) and normalize based on `mode` before using it.
2. Remove reliance on `as string` casts for runtime correctness; instead normalize values explicitly:
  - For single mode: coerce arrays to `''`.
  - For multiple mode: coerce non-arrays to `[]` (or `[string]` if you want to preserve a string value).
3. Apply the same normalization/default strategy in both `CraftPickerModal` and `CraftSelector` so the API behaves consistently.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment on lines +25 to +37
const props = withDefaults(
defineProps<{
visible: boolean;
modelValue: string | string[];
mode: 'single' | 'multiple';
title?: string;
}>(),
{
visible: false,
modelValue: () => [],
mode: 'single',
title: '',
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. Bad default modelvalue type 🐞 Bug ≡ Correctness

CraftPickerModal defaults mode to 'single' but defaults modelValue to [], so when the
modal opens the single-mode sync path wraps the array into localValue and can produce a nested
array (wrong shape) and incorrect emitted values. The same inconsistent default exists in
CraftSelector, so omitting modelValue can pass a non-string into the single-selector path.
Agent Prompt
## Issue description
`CraftPickerModal` and `CraftSelector` default `mode` to `'single'` but default `modelValue` to an array (`[]`). In single mode, `CraftPickerModal` wraps `props.modelValue` into `localValue` on open, and because `[]` is truthy this can create `localValue` with an invalid nested array shape (and then emit wrong values).

## Issue Context
- `CraftPickerModal` uses a `watch(() => props.visible, ...)` to sync `localValue` when opening; the single-mode branch assumes `props.modelValue` is a string.
- `CraftSelector` also defaults `modelValue` to `[]` while defaulting `mode` to `'single'`, and forwards the value as a string via a cast.

## Fix Focus Areas
- web/admin/src/views/dashboard/craft_flow/components/CraftPickerModal.vue[25-66]
- web/admin/src/views/dashboard/craft_flow/CraftSelector.vue[40-53]

## Suggested fix approach
1. Make `modelValue` default consistent with `mode` default:
   - Either default `modelValue` to `''` (string) when `mode` defaults to `'single'`, or
   - Make `modelValue` optional (default `undefined`) and normalize based on `mode` before using it.
2. Remove reliance on `as string` casts for runtime correctness; instead normalize values explicitly:
   - For single mode: coerce arrays to `''`.
   - For multiple mode: coerce non-arrays to `[]` (or `[string]` if you want to preserve a string value).
3. Apply the same normalization/default strategy in both `CraftPickerModal` and `CraftSelector` so the API behaves consistently.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Co-authored-by: Colin <Colin_XKL@outlook.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
web/admin/src/assets/style/tailwind.css (1)

1-2: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Stylelint will fail on Tailwind v4's @config/@import ordering — update stylelint config.

This ordering is correct per Tailwind v4 (Tailwind requires @config before @import to apply configuration), but the static analysis output shows stylelint flags no-invalid-position-at-import-rule and scss/at-rule-no-unknown on these exact lines. If stylelint runs in CI, this file will fail even though it's valid Tailwind v4 usage. Consider adding an override/ignore for these two rules on this file, or switching to a Tailwind-aware stylelint config.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/admin/src/assets/style/tailwind.css` around lines 1 - 2, Update the
Stylelint configuration for web/admin/src/assets/style/tailwind.css to allow
Tailwind v4’s required `@config` before `@import` ordering and recognize the `@config`
at-rule. Scope the override to this file where possible, disabling or ignoring
no-invalid-position-at-import-rule and scss/at-rule-no-unknown without changing
the stylesheet ordering.

Source: Linters/SAST tools

web/admin/tsconfig.json (1)

18-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

strictTemplates: false broadly disables Vue template type-checking.

This suppresses type errors across all templates rather than fixing the specific incompatibilities introduced by the Vue/TS/Arco upgrade, reducing the value of vue-tsc type-checking going forward.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/admin/tsconfig.json` around lines 18 - 20, Remove the
vueCompilerOptions.strictTemplates override from the admin TypeScript
configuration and resolve the specific Vue template type errors exposed by the
Vue/TypeScript/Arco upgrade, preserving strict template checking for vue-tsc.
web/admin/eslint.config.mjs (1)

54-54: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

no-debugger gated on build-time NODE_ENV.

The rule severity is fixed when ESLint's config loads based on process.env.NODE_ENV, not per invocation intent. If CI doesn't explicitly set NODE_ENV=production before linting, debugger statements won't be flagged even in a "production-bound" lint run.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/admin/eslint.config.mjs` at line 54, Update the no-debugger configuration
in the ESLint config so it is not gated by build-time process.env.NODE_ENV.
Configure the rule to consistently flag debugger statements during linting,
including production-bound CI runs regardless of the environment variable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@web/admin/src/views/dashboard/topic_feed/components/TopicAggregatorEditor.vue`:
- Around line 86-90: Update the numeric value conversion used by
TopicAggregatorEditor’s model-value binding to return undefined when step.value
is an empty string before applying Number conversion, following the existing
craft_atom.vue helper pattern; preserve normal numeric conversion for non-empty
values.

---

Nitpick comments:
In `@web/admin/eslint.config.mjs`:
- Line 54: Update the no-debugger configuration in the ESLint config so it is
not gated by build-time process.env.NODE_ENV. Configure the rule to consistently
flag debugger statements during linting, including production-bound CI runs
regardless of the environment variable.

In `@web/admin/src/assets/style/tailwind.css`:
- Around line 1-2: Update the Stylelint configuration for
web/admin/src/assets/style/tailwind.css to allow Tailwind v4’s required `@config`
before `@import` ordering and recognize the `@config` at-rule. Scope the override to
this file where possible, disabling or ignoring
no-invalid-position-at-import-rule and scss/at-rule-no-unknown without changing
the stylesheet ordering.

In `@web/admin/tsconfig.json`:
- Around line 18-20: Remove the vueCompilerOptions.strictTemplates override from
the admin TypeScript configuration and resolve the specific Vue template type
errors exposed by the Vue/TypeScript/Arco upgrade, preserving strict template
checking for vue-tsc.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1240cb62-0714-456a-8497-6ee16908c3e1

📥 Commits

Reviewing files that changed from the base of the PR and between 85838a2 and 64069d9.

⛔ Files ignored due to path filters (1)
  • web/admin/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (26)
  • web/admin/.eslintignore
  • web/admin/.eslintrc.js
  • web/admin/babel.config.js
  • web/admin/components.d.ts
  • web/admin/config/vite.config.dev.ts
  • web/admin/config/vite.config.prod.ts
  • web/admin/eslint.config.mjs
  • web/admin/package.json
  • web/admin/postcss.config.js
  • web/admin/src/api/interceptor.ts
  • web/admin/src/assets/style/tailwind.css
  • web/admin/src/env.d.ts
  • web/admin/src/utils/validator.ts
  • web/admin/src/views/dashboard/craft_atom/craft_atom.vue
  • web/admin/src/views/dashboard/craft_flow/CraftSelector.vue
  • web/admin/src/views/dashboard/craft_flow/components/CraftPickerModal.vue
  • web/admin/src/views/dashboard/curl_to_rss/curl_to_rss.vue
  • web/admin/src/views/dashboard/embedding_filter_debug/index.vue
  • web/admin/src/views/dashboard/feed_viewer/feed_viewer.vue
  • web/admin/src/views/dashboard/html_to_rss/html_to_rss.vue
  • web/admin/src/views/dashboard/topic_feed/components/TopicAggregatorEditor.vue
  • web/admin/src/views/dashboard/topic_feed/components/TopicInputSourcesEditor.vue
  • web/admin/src/views/dashboard/topic_feed/detail.vue
  • web/admin/src/views/dashboard/web_monitor/web_monitor.vue
  • web/admin/tsconfig.json
  • web/admin/vitest.config.ts
💤 Files with no reviewable changes (5)
  • web/admin/.eslintignore
  • web/admin/src/utils/validator.ts
  • web/admin/babel.config.js
  • web/admin/.eslintrc.js
  • web/admin/config/vite.config.dev.ts

Comment on lines +86 to +90
:model-value="toNumberValue(step.value)"
:min="1"
mode="button"
style="flex: 1; min-width: 150px"
@update:model-value="(value) => updateStepValue(idx, value)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
fd -a 'TopicAggregatorEditor\.vue|craft_atom\.vue' . || true

echo "== inspect TopicAggregatorEditor relevant lines =="
if [ -f web/admin/src/views/dashboard/topic_feed/components/TopicAggregatorEditor.vue ]; then
  nl -ba web/admin/src/views/dashboard/topic_feed/components/TopicAggregatorEditor.vue | sed -n '1,230p'
fi

echo "== search toNumberValue definitions/usages =="
rg -n "toNumberValue|Number\\(.*\\)|toNumber|value === ''|value == ''|''\\s*\\?|toNumber" web/admin/src/views/dashboard/topic_feed/components/TopicAggregatorEditor.vue web/admin/src/views -S || true

echo "== inspect craft_atom relevant lines if found =="
while IFS= read -r f; do
  echo "--- $f ---"
  wc -l "$f"
  sed -n '1,280p' "$f" | nl -ba
done < <(fd 'craft_atom\.vue' .)

Repository: Colin-XKL/FeedCraft

Length of output: 438


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== TopicAggregatorEditor.vue =="
awk '{printf "%6d\t%s\n", NR, $0}' web/admin/src/views/dashboard/topic_feed/components/TopicAggregatorEditor.vue | sed -n '1,230p'

echo "== craft_atom.vue relevant searches =="
for pat in "toNumberValue|toNumber|Number\\("; do
  echo "--- pattern: $pat ---"
  grep -nE "$pat|value === ''|value == ''" web/admin/src/views/dashboard/craft_atom/craft_atom.vue || true
done

echo "== read-only behavioral probe for Number conversion and equality semantics =="
node - <<'JS'
function current(v) {
  const r = Number(v);
  return Number.isNaN(r) ? undefined : r;
}
for (const v of ["", "0", "1", "abc"]) {
  console.log(JSON.stringify({value: v, current, modelMinOne: Number.isNaN(Number(v)) ? undefined : Math.max(1, Number(v)), rawNumberV: Number(v)}));
}
JS

Repository: Colin-XKL/FeedCraft

Length of output: 8556


Preserve empty numeric values as undefined.

Number('') returns 0, so a numeric step with value === '' is rendered as 0 despite min="1". Handle value === '' before numeric conversion, matching the existing craft_atom.vue helper pattern.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@web/admin/src/views/dashboard/topic_feed/components/TopicAggregatorEditor.vue`
around lines 86 - 90, Update the numeric value conversion used by
TopicAggregatorEditor’s model-value binding to return undefined when step.value
is an empty string before applying Number conversion, following the existing
craft_atom.vue helper pattern; preserve normal numeric conversion for non-empty
values.

Co-authored-by: Colin <Colin_XKL@outlook.com>
Co-authored-by: Colin <Colin_XKL@outlook.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants