Skip to content

Conversation

@DaxServer
Copy link
Owner

No description provided.

@coderabbitai
Copy link

coderabbitai bot commented Oct 17, 2025

📝 Walkthrough

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new custom Button component with configurable variants and sizes
    • Added Lucide icon library integration across the application
    • Implemented dark theme support with comprehensive color scheme
  • Style

    • Updated all buttons to use modern variant styling (outline, secondary, destructive, etc.)
    • Replaced icon set throughout UI components for visual consistency
    • Added CSS theme system with semantic color tokens
  • Chores

    • Updated linting configuration from ESLint to Biome
    • Added new UI and utility dependencies

Walkthrough

Replaces ESLint auto-import config with Biome/biomelintrc entries, adds a new Button component, class utility and design system (Reka UI, Lucide icons, Tailwind theme), updates TypeScript paths and auto-import/type declarations, and refactors ~20+ frontend components to use the new Button and icon slots.

Changes

Cohort / File(s) Summary
Linting & ignore
\.biomeignore, biome.json
Removed several ignore patterns; disabled noUnusedImports for Vue overrides in Biome config.
Auto-import / globals & ESLint file changes
frontend/.biomelintrc-auto-import.json, frontend/.eslintrc-auto-import.json
Added Biome auto-import globals file; removed previous ESLint auto-import JSON.
Type declarations & component registry
frontend/auto-imports.d.ts, frontend/components.d.ts, frontend/interface-extensions.d.ts, frontend/components.json
Added ambient globals (Button, RefreshCcw, buttonVariants, cn) and exported ButtonVariants type; switched Button GlobalComponents type to local Button.vue; added components.json with aliases and theme metadata.
New UI primitives & utility
frontend/src/components/ui/button/Button.vue, frontend/src/components/ui/button/index.ts, frontend/src/lib/utils.ts, frontend/auto-imports.d.ts
Introduced Button component wrapping reka-ui Primitive, exported buttonVariants (cva) and ButtonVariants type, and added cn() util (clsx + tailwind-merge).
Styling & theme
frontend/src/assets/base.css
Added tw-animate-css import, defined comprehensive CSS variable theme (light/dark) and base layer, added custom dark variant.
Component updates (icons & Button slot migration)
frontend/src/features/wikibase-schema/components/*.vue, frontend/src/features/data-processing/components/*.vue, frontend/src/features/project-management/pages/OpenProject.vue, frontend/src/shared/components/Header.vue
Replaced PrimeVue Button prop-based API with the new Button (variant/size) and slot-based icon content using lucide-vue-next across ~20+ components; adjusted some emits/signatures (WikibaseSchemaEditor emits: added save and help).
Build / config / paths
frontend/vite.config.ts, frontend/tsconfig.json, frontend/package.json
Switched Vite config to use biomelintrc key, updated TS path aliases (@frontend/*./src/*), added "gen" script, and added new dependencies (class-variance-authority, clsx, lucide-vue-next, reka-ui, tailwind-merge, tw-animate-css).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant PageComponent as Component
    participant ButtonComponent as Button
    participant Variants as buttonVariants
    participant CN as cn (clsx+twMerge)
    Note over ButtonComponent Variants CN #DDEBF7: New Button render & class composition flow

    User->>PageComponent: clicks action (Add/Delete/Refresh)
    PageComponent->>ButtonComponent: render with props (variant, size, class) + slot icon/text
    ButtonComponent->>Variants: compute variant classes
    Variants-->>ButtonComponent: variant class string
    ButtonComponent->>CN: merge classes (base + variant + passed class)
    CN-->>ButtonComponent: final classString
    ButtonComponent->>User: emit click / perform action (UI updates)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning No pull request description was provided by the author. The description field is entirely empty, which means there is no content to evaluate against the changeset. According to the pass criterion, a description should be "related in some way to the changeset," but an absent description cannot satisfy this requirement. Without any descriptive content, the description fails to provide even minimal information about the changes being made. Add a pull request description that explains the purpose and scope of the changes. Even a brief description relating the migration effort to the new Button component system, the rationale for adopting shadcn-style UI patterns, and the affected components would satisfy the requirement. Given that the PR involves significant refactoring across multiple systems (Button component, icon library, linting configuration), a description would help reviewers understand the intent and scope of the migration.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "feat: migrate to shadcn Button" directly corresponds to a significant and intentional change in this pull request. The changeset introduces a new Button component based on reka-ui (at frontend/src/components/ui/button/), defines visual variants using class-variance-authority, and replaces PrimeVue Button usage with this new component throughout multiple files in the codebase. While the PR encompasses additional changes (icon system migration, linting configuration updates, and CSS styling), the Button component migration represents the primary architectural change that aligns with the title. The title is specific and clear enough that a teammate reviewing history would understand the main focus.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch shadcn-button

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/features/wikibase-schema/components/WikibaseSchemaEditor.vue (1)

156-166: Remove unused PrimeVue helper functions.

The helper functions getSaveButtonIcon() and getSaveButtonSeverity() return PrimeVue-specific values (PrimeReact icon class names and severity strings) that are no longer used by the new Button component. After migrating the Save button to use inline conditional icons (see previous comment), these functions should be removed.

Apply this diff to remove the unused helpers:

-const getSaveButtonIcon = () => {
-  if (isSaving.value) return 'pi pi-spin pi-spinner'
-  if (saveStatus.value === 'success' && !schemaStore.isDirty) return 'pi pi-check'
-  if (saveStatus.value === 'error') return 'pi pi-times'
-  return 'pi pi-save'
-}
-
-const getSaveButtonSeverity = () => {
-  if (saveStatus.value === 'success' && !schemaStore.isDirty) return 'success'
-  if (saveStatus.value === 'error') return 'danger'
-  return undefined
-}
-
🧹 Nitpick comments (5)
biome.json (1)

73-73: Verify that disabling noUnusedImports for Vue files is intentional.

Disabling noUnusedImports in addition to noUnusedVariables for all Vue files will suppress warnings about unused imports, which could mask actual issues where developers manually add imports that are never used.

If this is specifically to accommodate auto-imports (which generate imports automatically), consider using a more targeted approach or documenting this decision.

frontend/src/features/wikibase-schema/components/StatementManager.vue (1)

34-40: Specify explicit Button variant for consistency.

This Button lacks a variant prop, making it rely on the default variant. For consistency with other buttons in this PR (e.g., PropertyValueList.vue uses variant="outline" for add actions), specify an explicit variant.

Apply this diff:

       <Button
         size="sm"
+        variant="outline"
         @click="handleAddStatement"
       >
         <LucidePlus />
         Add Statement
       </Button>
frontend/src/shared/components/Header.vue (1)

27-30: Specify explicit Button size for consistency.

This Button lacks a size prop. For consistency with other buttons throughout this PR (which predominantly use size="sm"), specify an explicit size.

Apply this diff:

-          <Button variant="outline">
+          <Button variant="outline" size="sm">
             <LucideMoveLeft />
             Back to Projects
           </Button>
frontend/src/components/ui/button/index.ts (1)

6-34: LGTM! buttonVariants definition is comprehensive and well-designed.

The cva configuration provides:

  • Robust base styling with focus states, disabled states, and SVG size handling
  • Six semantic variant options with appropriate color schemes
  • Seven size options including dedicated icon button sizes
  • Smart use of has-[>svg] selector to adjust padding when icons are present
  • Dark mode support for relevant variants
  • Sensible defaults (variant: 'default', size: 'default')

The base classes string on line 7 is quite long but follows the common pattern for shadcn-style button variants.

If you prefer improved readability, consider formatting the base classes string across multiple lines:

export const buttonVariants = cva(
  [
    "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md",
    "text-sm font-medium transition-all",
    "disabled:pointer-events-none disabled:opacity-50",
    "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
    "shrink-0 [&_svg]:shrink-0 outline-none",
    "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
    "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
  ].join(" "),
  {
    // ... rest of config
  }
)
frontend/src/components/ui/button/Button.vue (1)

23-23: The hover:cursor-pointer class is optional but not harmful.

Based on verification, buttonVariants does not include cursor styling. For native <button> elements, the cursor pointer is implicit browser behavior, making this class technically redundant. However, since <Primitive> can render as different elements (controlled by the as prop), keeping the explicit class ensures consistent pointer styling across variants and maintains defensive styling. Removing it is safe for the default button behavior but optional—this is a style consistency preference rather than a necessity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7427323 and cd046c8.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (34)
  • .biomeignore (0 hunks)
  • biome.json (1 hunks)
  • frontend/.biomelintrc-auto-import.json (1 hunks)
  • frontend/.eslintrc-auto-import.json (0 hunks)
  • frontend/auto-imports.d.ts (12 hunks)
  • frontend/components.d.ts (1 hunks)
  • frontend/components.json (1 hunks)
  • frontend/interface-extensions.d.ts (0 hunks)
  • frontend/package.json (2 hunks)
  • frontend/src/assets/base.css (1 hunks)
  • frontend/src/components/ui/button/Button.vue (1 hunks)
  • frontend/src/components/ui/button/index.ts (1 hunks)
  • frontend/src/features/data-processing/components/ColumnHeaderMenu.vue (2 hunks)
  • frontend/src/features/data-processing/components/ReplaceDialog.vue (2 hunks)
  • frontend/src/features/project-management/pages/OpenProject.vue (4 hunks)
  • frontend/src/features/wikibase-schema/components/ClaimEditor.vue (3 hunks)
  • frontend/src/features/wikibase-schema/components/DropZone.vue (2 hunks)
  • frontend/src/features/wikibase-schema/components/PropertyValueItem.vue (2 hunks)
  • frontend/src/features/wikibase-schema/components/PropertyValueList.vue (2 hunks)
  • frontend/src/features/wikibase-schema/components/QualifiersEditor.vue (3 hunks)
  • frontend/src/features/wikibase-schema/components/ReferenceContainer.vue (2 hunks)
  • frontend/src/features/wikibase-schema/components/ReferencesEditor.vue (5 hunks)
  • frontend/src/features/wikibase-schema/components/SchemaSelector.vue (3 hunks)
  • frontend/src/features/wikibase-schema/components/StatementEditor.vue (4 hunks)
  • frontend/src/features/wikibase-schema/components/StatementManager.vue (2 hunks)
  • frontend/src/features/wikibase-schema/components/TermSection.vue (2 hunks)
  • frontend/src/features/wikibase-schema/components/ValidationDisplay.vue (5 hunks)
  • frontend/src/features/wikibase-schema/components/ValueMappingEditor.vue (1 hunks)
  • frontend/src/features/wikibase-schema/components/WikibaseSchemaEditor.vue (5 hunks)
  • frontend/src/features/wikibase-schema/composables/useValueMapping.ts (2 hunks)
  • frontend/src/lib/utils.ts (1 hunks)
  • frontend/src/shared/components/Header.vue (2 hunks)
  • frontend/tsconfig.json (1 hunks)
  • frontend/vite.config.ts (1 hunks)
💤 Files with no reviewable changes (3)
  • frontend/interface-extensions.d.ts
  • .biomeignore
  • frontend/.eslintrc-auto-import.json
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/src/components/ui/button/index.ts (1)
frontend/auto-imports.d.ts (1)
  • ButtonVariants (415-415)
frontend/auto-imports.d.ts (3)
frontend/src/shared/types/wikibase-schema.ts (1)
  • ValidationMessages (40-49)
frontend/src/components/ui/button/index.ts (1)
  • buttonVariants (6-34)
frontend/src/lib/utils.ts (1)
  • cn (5-7)
🪛 GitHub Actions: Typecheck code
frontend/src/features/data-processing/components/ColumnHeaderMenu.vue

[error] 177-177: TypeScript error TS7006: Parameter 'event' implicitly has an 'any' type.

🔇 Additional comments (33)
frontend/tsconfig.json (1)

17-18: LGTM!

The path mapping update correctly simplifies the @frontend/* alias to be relative to the frontend directory, while maintaining the appropriate relative path for @backend/*.

frontend/package.json (1)

9-9: LGTM!

The new dependencies and gen script appropriately support the shadcn-vue migration. The package versions align with current stable releases.

Based on learnings: The versions match the documented stable releases for class-variance-authority (0.7.1), clsx (2.1.1), tailwind-merge (3.3.1), and lucide-vue-next (0.5xx series).

Also applies to: 18-19, 22-22, 26-27, 29-29

frontend/src/assets/base.css (1)

3-5: LGTM!

The theme system is well-structured with:

  • Proper CSS variable mapping through @theme inline
  • OKLCH color space for better color perception
  • Comprehensive light and dark theme definitions
  • Appropriate base layer utilities

The custom dark variant and tw-animate-css import align with modern Tailwind CSS practices.

Also applies to: 12-49, 51-66, 69-120, 122-129

frontend/src/features/wikibase-schema/composables/useValueMapping.ts (1)

5-5: LGTM!

The migration from string-based icons to Lucide component objects is consistent with the PR's overall pattern. The icon choices are semantically appropriate:

  • LucideDatabase for column data sources
  • LucideLock for constant values
  • LucideCode for expressions

Consumers correctly render these using <component :is="option.icon" /> (as seen in ValueMappingEditor.vue).

Also applies to: 26-28

frontend/src/features/wikibase-schema/components/ValueMappingEditor.vue (1)

137-148: LGTM!

The Button implementation correctly:

  • Uses the new variant prop API (default vs secondary)
  • Renders icons as dynamic components via <component :is="option.icon" />
  • Includes both icon and label text for accessibility
  • Uses the standardized sm size value

The pattern is consistent with the broader shadcn Button migration.

frontend/vite.config.ts (1)

90-92: The biomelintrc property is correctly used and fully supported.

unplugin-auto-import includes a biomelintrc option (with enabled and filepath settings) to generate a .biomelintrc-auto-import.json for Biome integration. The property name change from eslintrc to biomelintrc is valid and intentional for Biome support. The configuration will be properly recognized and processed.

frontend/src/features/wikibase-schema/components/PropertyValueList.vue (1)

2-2: LGTM!

The Button migration is correct: LucidePlus icon semantically matches the add action, variant and size props are appropriate, and the slot-based content is properly structured.

Also applies to: 48-56

frontend/src/features/wikibase-schema/components/ReferenceContainer.vue (1)

2-2: LGTM!

The Button migration is well-executed: icon choices are semantically correct (LucidePlus for add, LucideTrash for remove), variant selections are appropriate (secondary for add, destructive for remove), and the slot-based structure is consistent.

Also applies to: 40-56

frontend/src/features/wikibase-schema/components/TermSection.vue (1)

2-2: LGTM!

The Button migration is correct: LucideX icon is appropriate for the remove action, variant="destructive" semantically matches the action, and the slot-based content is properly structured.

Also applies to: 174-181

frontend/components.json (1)

1-21: LGTM!

The shadcn-vue configuration is well-structured: the icon library correctly specifies lucide (matching the Lucide icons used throughout the PR), path aliases align with the TypeScript configuration, and the Tailwind settings (CSS variables, neutral base color, new-york style) provide a solid foundation for the UI migration.

frontend/components.d.ts (1)

13-13: LGTM! Button type declaration updated correctly.

The global component type reference has been successfully migrated from PrimeVue's Button to the local custom implementation.

frontend/src/features/data-processing/components/ColumnHeaderMenu.vue (1)

2-2: LGTM! Lucide icon import added correctly.

The import of LucideChevronDown aligns with the project-wide migration to Lucide icons.

frontend/.biomelintrc-auto-import.json (1)

1-426: LGTM! Auto-import configuration looks comprehensive.

The new Biome-based auto-import configuration correctly includes the migrated Button-related globals (Button, ButtonVariants, buttonVariants, cn) alongside existing project globals. The structure is well-formed and aligns with the broader migration from ESLint to Biome tooling.

frontend/src/features/data-processing/components/ReplaceDialog.vue (2)

2-2: LGTM! Lucide icons imported correctly.

The import of LucideReplace and LucideX follows the project-wide pattern for icon migration.


150-166: LGTM! Dialog footer buttons migrated correctly.

Both Cancel and Replace buttons have been successfully migrated to the slot-based icon approach while preserving all functional behavior (disabled states, loading state, click handlers). The icon choices (LucideX for Cancel, LucideReplace for Replace) are semantically appropriate.

frontend/src/features/wikibase-schema/components/ValidationDisplay.vue (2)

2-2: LGTM! Lucide icons imported correctly.

The import of LucideTrash and LucideX follows the established migration pattern.


244-252: LGTM! All validation display buttons migrated consistently.

All four button instances (error dismiss, warning dismiss, and two clear-all buttons) have been successfully migrated to the slot-based icon approach with consistent size="sm" and variant="secondary" styling. The icon choices are semantically appropriate and all functional behavior is preserved.

Also applies to: 276-284, 294-301, 340-349

frontend/src/features/wikibase-schema/components/ClaimEditor.vue (2)

2-2: LGTM! Lucide icons imported correctly.

The import of statement rank icons (LucideStar, LucideCircle, LucideCircleX) follows the established pattern.


22-26: LGTM! Rank selection buttons migrated elegantly.

The migration uses a clean pattern where Lucide icon components are stored in the rankOptions data structure and rendered dynamically via <component :is="option.icon" />. The variant logic correctly highlights the selected rank, and the icon choices are semantically appropriate (Star for preferred, Circle for normal, CircleX for deprecated).

Also applies to: 52-63

frontend/src/components/ui/button/index.ts (2)

1-4: LGTM! Button component exports set up correctly.

The imports from class-variance-authority and the Button component export follow best practices for a variant-driven component system.


36-36: LGTM! ButtonVariants type export is correct.

The type export using VariantProps correctly infers the prop types from the buttonVariants definition, enabling type-safe usage across components.

frontend/src/features/wikibase-schema/components/SchemaSelector.vue (1)

125-128: LGTM: slot-based Button migration is correct.

Icons render via slots, variants/sizes align with buttonVariants, and labels ensure accessibility.

Also applies to: 172-180

frontend/src/features/wikibase-schema/components/ReferencesEditor.vue (1)

62-69: LGTM: add actions migrated cleanly.

Secondary + sm with icon and text reads well and remains accessible.

Also applies to: 99-106

frontend/src/features/wikibase-schema/components/StatementEditor.vue (3)

169-175: LGTM: “Add New Claim” migration.

Outline variant with icon+label is consistent with the new Button API.


185-191: LGTM: New statement actions.

Clear labels, proper disabled state on Save; looks good.

Also applies to: 194-197


121-129: ****

The method removeStatement1 exists in the store (line 386 of schema.store.ts) and will not throw at runtime. Both removeStatement and removeStatement1 are intentionally defined and exported methods—they serve different purposes: removeStatement modifies both the statements array and statements1 dict, while removeStatement1 only modifies statements1. The call at line 126 is valid.

Likely an incorrect or invalid review comment.

frontend/src/features/project-management/pages/OpenProject.vue (1)

64-65: LGTM: empty state and create actions.

Lucide icon usage and slot-based buttons look consistent.

Also applies to: 69-72

frontend/auto-imports.d.ts (1)

489-490: The review comment is based on incorrect assumptions about auto-generated files.

Button is already registered in components.d.ts line 13 as part of the GlobalComponents interface. Both auto-imports.d.ts and components.d.ts are auto-generated by unplugin-auto-import and unplugin-vue-components respectively, as confirmed by their file headers and the vite.config.ts configuration which sets dts: true for both plugins.

The empty GlobalComponents interface in auto-imports.d.ts is a separate module augmentation from unplugin-auto-import. Manual edits to auto-generated files will be overwritten on the next build. The concern is invalid because:

  1. Button is already properly type-available in templates via components.d.ts
  2. Button is also available globally in scripts (via declare global)
  3. TypeScript correctly merges the two separate declare module 'vue' blocks

No changes are needed to the code.

Likely an incorrect or invalid review comment.

frontend/src/features/wikibase-schema/components/WikibaseSchemaEditor.vue (5)

201-209: Icon-only button with aria-label is acceptable.

The back button uses size="icon" with only an icon and aria-label. This is acceptable for accessibility, though visually-hidden text is sometimes preferred for screen readers.


245-264: Button migrations look good.

The Add item and Preview buttons correctly use the new Button API with variant="outline", size="sm", inline Lucide icons, and descriptive text labels.


278-286: Help button migration looks good.

The Help button correctly uses the new Button API with variant="outline", size="sm", inline Lucide icon, and descriptive text.


311-314: Empty state button looks good.

The button correctly uses slot-based content with icon and text. Missing explicit variant/size props is acceptable as defaults will apply.


329-339: Item action buttons look good.

Both Edit and Delete buttons correctly use the new Button API with appropriate sizes, the destructive variant for delete, inline Lucide icons, and descriptive text labels.

Comment on lines +67 to +68
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.577 0.245 27.325);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix destructive color contrast issue.

The --destructive and --destructive-foreground variables are set to the same OKLCH value oklch(0.577 0.245 27.325), which would render text invisible on destructive-colored backgrounds in light mode. The foreground should be a contrasting color (typically white or very light).

Apply this diff to fix the contrast:

   --destructive: oklch(0.577 0.245 27.325);
-  --destructive-foreground: oklch(0.577 0.245 27.325);
+  --destructive-foreground: oklch(0.985 0 0);

Note: The dark theme (lines 102-103) correctly uses different values for background and foreground.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.577 0.245 27.325);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.985 0 0);
🤖 Prompt for AI Agents
In frontend/src/assets/base.css around lines 67 to 68, the --destructive and
--destructive-foreground variables are currently identical, making destructive
text invisible on destructive-colored backgrounds in light mode; update
--destructive-foreground to a high-contrast, very light value (e.g., a
near-white OKLCH or plain white) so text is readable on the destructive
background, and ensure this mirrors the intent of the dark-theme pair on lines
~102-103 (background darker, foreground light).

Comment on lines +139 to 146
variant="destructive"
size="sm"
class="p-button-sm delete-button"
@click="deleteProject(data)"
/>
>
<LucideTrash />
</Button>
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Remove legacy PrimeVue props/classes; add an accessible name.

icon="pi pi-trash" and p-button-sm are leftovers and ineffective with the new Button.

-<Button
-  icon="pi pi-trash"
-  variant="destructive"
-  size="sm"
-  class="p-button-sm delete-button"
-  @click="deleteProject(data)"
->
-  <LucideTrash />
-</Button>
+<Button
+  aria-label="Delete project"
+  variant="destructive"
+  size="icon-sm"
+  class="delete-button"
+  @click="deleteProject(data)"
+>
+  <LucideTrash />
+  <span class="sr-only">Delete project</span>
+</Button>

Optional: grep for other leftover icon="pi or p-button- classes:


🏁 Script executed:

#!/bin/bash
rg -nP 'icon\s*=\s*"pi ' -g 'frontend/**/*.vue' -C2
rg -nP '\bp-button-(sm|lg|outlined)\b' -g 'frontend/**/*.vue' -C2

Length of output: 3092


Verified: Remove legacy PrimeVue props and add accessible name to the delete button.

The script confirms the target file still contains both icon="pi pi-trash" (line 138) and class="p-button-sm" (line 141). The suggested refactor is correct—these props are indeed leftovers from PrimeVue and ineffective with the new Button component. The diff properly:

  • Removes the unused icon prop
  • Changes size="sm" to size="icon-sm" (appropriate for icon-only buttons)
  • Removes the legacy p-button-sm class
  • Adds aria-label="Delete project" for screen readers
  • Adds <span class="sr-only"> as an additional accessibility layer

The broader grep also identified 4 other instances of icon="pi " in ValueMappingEditor.vue and TermsEditor.vue that should be audited for similar legacy prop cleanup.

🤖 Prompt for AI Agents
In frontend/src/features/project-management/pages/OpenProject.vue around lines
139 to 146, the delete Button still uses legacy PrimeVue props and classes
(icon="pi pi-trash" and class="p-button-sm") and lacks an accessible name;
remove the unused icon prop and the legacy class, change size="sm" to
size="icon-sm" for an icon-only button, add aria-label="Delete project" and
include a visually hidden <span class="sr-only">Delete project</span> inside the
button; also audit ValueMappingEditor.vue and TermsEditor.vue for remaining
icon="pi ..." occurrences and apply the same cleanup and accessibility addition
where applicable.

Comment on lines 65 to +71
<Button
icon="pi pi-trash"
severity="danger"
size="small"
text
variant="destructive"
size="sm"
@click="removeQualifier(qualifier.id)"
/>
>
<LucideTrash />
</Button>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add accessible label to icon-only button.

The remove button renders only an icon without visible text, which creates an accessibility issue for screen reader users. Icon-only buttons should include an aria-label attribute or visually-hidden text to describe the action.

Apply this diff to add an accessible label:

       <Button
         variant="destructive"
         size="sm"
+        aria-label="Remove qualifier"
         @click="removeQualifier(qualifier.id)"
       >
         <LucideTrash />
       </Button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Button
icon="pi pi-trash"
severity="danger"
size="small"
text
variant="destructive"
size="sm"
@click="removeQualifier(qualifier.id)"
/>
>
<LucideTrash />
</Button>
<Button
variant="destructive"
size="sm"
aria-label="Remove qualifier"
@click="removeQualifier(qualifier.id)"
>
<LucideTrash />
</Button>
🤖 Prompt for AI Agents
In frontend/src/features/wikibase-schema/components/QualifiersEditor.vue around
lines 65 to 71 the icon-only remove button lacks an accessible label; update the
Button to include an aria-label (for example aria-label="Remove qualifier") or
add visually-hidden text describing the action (optionally including the
qualifier id or name for context), ensuring the label is localized if the app
uses i18n so screen readers can announce the purpose of the button.

Comment on lines +83 to 89
variant="destructive"
size="sm"
@click="removeReference(reference.id)"
/>
>
<LucideTrash />
</Button>
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add accessible names to icon‑only destructive buttons; consider icon‑sm size.

Icon-only buttons should expose an accessible label. Also, use the square icon size for consistency.

Apply one of these patterns:

  1. Add aria-label:
-  <Button
+  <Button
+    aria-label="Delete reference"
     variant="destructive"
-    size="sm"
+    size="icon-sm"
     @click="removeReference(reference.id)"
   >
     <LucideTrash />
   </Button>
-  <Button
+  <Button
+    aria-label="Remove snak"
     variant="destructive"
-    size="sm"
+    size="icon-sm"
     @click="removeSnakFromReference(reference.id, snak.id)"
   >
     <LucideX />
   </Button>
  1. Or add visually hidden text:
   <Button variant="destructive" size="icon-sm" @click="removeReference(reference.id)">
     <LucideTrash />
+    <span class="sr-only">Delete reference</span>
   </Button>

Also applies to: 117-123

🤖 Prompt for AI Agents
In frontend/src/features/wikibase-schema/components/ReferencesEditor.vue around
lines 83-89 and 117-123, the icon-only destructive buttons lack accessible names
and should use the square icon size for consistency; update each Button to
either include an aria-label (e.g., aria-label="Remove reference") or add
visually hidden text inside the button for screen readers, and change the Lucide
icon to the square "icon-sm" sizing so the icon is consistently sized and
accessible.

Comment on lines 100 to 109
<Button
v-if="canMoveUp"
v-tooltip="'Move up'"
icon="pi pi-chevron-up"
size="small"
severity="secondary"
text
size="sm"
variant="secondary"
@click="$emit('move-up')"
/>
>
<LucideChevronUp />
</Button>

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add accessible names to icon‑only buttons; use icon‑sm size.

Improve a11y and visual consistency for move/remove controls.

-<Button v-if="canMoveUp" v-tooltip="'Move up'" size="sm" variant="secondary" @click="$emit('move-up')">
+<Button v-if="canMoveUp" aria-label="Move up" size="icon-sm" variant="secondary" @click="$emit('move-up')">
   <LucideChevronUp />
 </Button>

-<Button v-if="canMoveDown" v-tooltip="'Move down'" size="sm" variant="secondary" @click="$emit('move-down')">
+<Button v-if="canMoveDown" aria-label="Move down" size="icon-sm" variant="secondary" @click="$emit('move-down')">
   <LucideChevronDown />
 </Button>

-<Button v-tooltip="'Remove statement'" size="sm" variant="destructive" @click="schemaStore.removeStatement(statement.id)">
+<Button aria-label="Remove statement" size="icon-sm" variant="destructive" @click="schemaStore.removeStatement(statement.id)">
   <LucideTrash />
 </Button>

Also applies to: 111-120, 123-130

Comment on lines +5 to +7
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix the argument spreading in the cn function.

The clsx function expects variadic arguments, but you're passing the entire inputs array as a single argument. This will not correctly process the class values.

Apply this diff:

 export function cn(...inputs: ClassValue[]) {
-  return twMerge(clsx(inputs))
+  return twMerge(clsx(...inputs))
 }
🤖 Prompt for AI Agents
In frontend/src/lib/utils.ts around lines 5 to 7, the cn function passes the
inputs array as a single argument to clsx which expects variadic arguments;
change the call to spread the inputs into clsx (i.e., use clsx(...inputs)) so
clsx processes each ClassValue correctly, then pass the resulting string to
twMerge as before.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
frontend/src/features/project-management/pages/OpenProject.vue (1)

144-151: Complete the delete button migration and add accessibility.

The previous review's suggestions were only partially applied. The button still has the legacy p-button-sm class, uses size="sm" instead of size="icon-sm" for an icon-only button, and lacks accessibility attributes.

Apply this diff to complete the migration:

 <Button
+  aria-label="Delete project"
   variant="destructive"
-  size="sm"
-  class="p-button-sm delete-button"
+  size="icon-sm"
+  class="delete-button"
   @click="deleteProject(data)"
 >
   <LucideTrash />
+  <span class="sr-only">Delete project</span>
 </Button>
🧹 Nitpick comments (2)
frontend/src/features/data-processing/components/ColumnHeaderMenu.vue (1)

169-180: TypeScript error resolved; consider more precise typing or cleaner handler.

The explicit Event type fixes the pipeline error from the previous review. The Button migration to slot-based icon content is correct.

For improved type precision or cleaner code, consider one of these alternatives:

Option 1: Use the more specific MouseEvent type:

-      @click="(event: Event) => menu.toggle(event)"
+      @click="(event: MouseEvent) => menu.toggle(event)"

Option 2: Pass the method reference directly (cleanest):

-      @click="(event: Event) => menu.toggle(event)"
+      @click="menu.toggle"

Minor formatting nit (Line 179):

-      <LucideChevronDown  />
+      <LucideChevronDown />
frontend/src/features/project-management/pages/OpenProject.vue (1)

110-110: Migrate the remaining PrimeVue icon to Lucide.

This PrimeVue icon (pi pi-file) should be replaced with a Lucide icon for consistency with the rest of the migration.

Consider using LucideFile or LucideFileText:

+import { ..., LucideFile } from 'lucide-vue-next'

Then replace the icon:

-<i class="pi pi-file text-lg text-blue-600" />
+<LucideFile class="text-blue-600" :size="18" />
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd046c8 and f2e742b.

📒 Files selected for processing (4)
  • frontend/src/features/data-processing/components/ColumnHeaderMenu.vue (2 hunks)
  • frontend/src/features/project-management/pages/OpenProject.vue (4 hunks)
  • frontend/src/features/wikibase-schema/components/DropZone.vue (2 hunks)
  • frontend/src/features/wikibase-schema/components/WikibaseSchemaEditor.vue (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/features/wikibase-schema/components/DropZone.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (13)
frontend/src/features/data-processing/components/ColumnHeaderMenu.vue (1)

2-2: LGTM!

The Lucide icon import is correct and properly used in the template.

frontend/src/features/project-management/pages/OpenProject.vue (5)

2-8: Clean icon imports for the migration.

All necessary Lucide icons are imported to replace PrimeVue icons throughout the component.


39-47: Well done addressing the previous loading prop issue!

The refresh button now correctly uses :disabled="isLoading" with conditional icon rendering (animated spinner vs. refresh icon) and dynamic text. This properly replaces the unsupported loading prop.


49-52: Proper slot-based Button implementation.

The create button correctly uses the new Button component's slot pattern with the Lucide icon.


69-71: Good empty state improvements.

The addition of flex-col ensures proper vertical layout, and the explicit :size="32" prop provides consistent icon sizing.


76-79: Consistent Button implementation.

Matches the pattern used for the header create button—clean and consistent.

frontend/src/features/wikibase-schema/components/WikibaseSchemaEditor.vue (7)

2-13: LGTM! All imported Lucide icons are used.

The icon imports are clean and all are utilized in the template for the button migration.


196-204: LGTM! Icon button migration is correct.

The back button properly uses size="icon" for icon-only buttons and includes an aria-label for accessibility.


240-249: LGTM! Toolbar buttons are properly migrated.

The Add item, Preview, and Help buttons consistently use variant="outline" and size="sm" with Lucide icons rendered in the button slots alongside text labels. The migration is clean and complete.

Also applies to: 250-259, 273-281


260-272: Save button migration successfully addresses past concerns.

The save button now properly uses the shadcn Button API:

  • Removed PrimeVue-specific props (:icon, :severity, :loading)
  • Conditional icon rendering in the slot based on state
  • Dynamic variant via :variant prop
  • Proper loading state with LucideLoader2 and animate-spin class

This resolves the incomplete migration flagged in the previous review.


306-309: LGTM! Empty state button uses default styling appropriately.

The button correctly uses the default variant (no explicit variant prop), which is appropriate for the primary action in an empty state.


324-327: Verify the missing variant prop on Edit button is intentional.

The Edit button at line 324 doesn't specify a variant prop, so it will use the default variant. This differs from the toolbar buttons (Add item, Preview, Help) which use variant="outline".

Please confirm whether this is intentional based on the different context (item actions vs. toolbar actions), or if it should be consistent with other secondary actions.


328-335: LGTM! Delete button properly uses destructive variant.

The delete button correctly uses variant="destructive" for a destructive action, with appropriate icon and text labels.

Comment on lines 159 to 163
const getSaveButtonSeverity = () => {
if (saveStatus.value === 'success' && !schemaStore.isDirty) return 'success'
if (saveStatus.value === 'error') return 'danger'
return undefined
if (saveStatus.value === 'success' && !schemaStore.isDirty) return 'default'
if (saveStatus.value === 'error') return 'destructive'
return 'outline'
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Rename function to match its new purpose.

The function name getSaveButtonSeverity() is misleading since it now returns shadcn Button variant values ('default', 'destructive', 'outline') rather than PrimeVue severity values.

Apply this diff to rename the function:

-const getSaveButtonSeverity = () => {
+const getSaveButtonVariant = () => {
   if (saveStatus.value === 'success' && !schemaStore.isDirty) return 'default'
   if (saveStatus.value === 'error') return 'destructive'
   return 'outline'
 }

And update the call site at line 262:

           <Button
             data-testid="save-btn"
-            :variant="getSaveButtonSeverity()"
+            :variant="getSaveButtonVariant()"
             :disabled="!canSave || isSaving"
             size="sm"

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In frontend/src/features/wikibase-schema/components/WikibaseSchemaEditor.vue
around lines 159 to 163, the function getSaveButtonSeverity() now returns shadcn
Button variant strings but its name is misleading; rename it to
getSaveButtonVariant and update the call site at line 262 to use
getSaveButtonVariant(); keep the same return values and behavior, and ensure any
other references to the old name in this file are updated to the new name.

@DaxServer DaxServer merged commit 6009ef6 into main Oct 18, 2025
6 checks passed
@DaxServer DaxServer deleted the shadcn-button branch October 18, 2025 10:46
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