Skip to content

📁 refactor: Prompts UI#11570

Merged
danny-avila merged 72 commits into
devfrom
refactor/prompts-components
Mar 22, 2026
Merged

📁 refactor: Prompts UI#11570
danny-avila merged 72 commits into
devfrom
refactor/prompts-components

Conversation

@berry-13

@berry-13 berry-13 commented Jan 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR improves the prompt group system with better usage tracking, smarter sorting, stronger validation, and some UI/code cleanup

Usage Tracking
A new POST /groups/:groupId/use endpoint and incrementPromptGroupUsage backend method now increment a numberOfGenerations counter each time a prompt group is used. The prompt command UI has been updated to call this endpoint on every use

Sorting & Pagination
Prompt groups are now sorted by numberOfGenerations (descending), then updatedAt, then _id, so the most-used groups bubble to the top. Cursor-based pagination has been updated accordingly to include numberOfGenerations for accurate results

Validation & Error Handling
Prompt creation now enforces non-empty text and valid types. Group ID parameters are validated in API routes. console.error calls have been replaced with logger.error, and all endpoints return proper error responses for invalid or missing resources

Frontend Changes
Imports for CategoryIcon and VariableDialog now use barrel exports. Two new chat settings toggles have been added ("always make production" and "auto send prompts"), and the unused AdvancedSwitch component has been removed

Code Cleanup
The unused createGroupPipeline function has been removed. Filter and query parameter handling in prompt group routes has been streamlined, and all queries now use consistent sorting and projection fields

Before After

Change Type

  • Style
  • Refactor
  • New feature (non-breaking change which adds functionality)

Testing

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • I have commented in any complex areas of my code
  • My changes do not introduce new warnings
  • I have written tests demonstrating that my changes are effective or that my feature works
  • Local unit tests pass with my changes
  • Any changes dependent on mine have been merged and published in downstream modules.

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Unused i18next Keys Detected

The following translation keys are defined in translation.json but are not used in the codebase:

  • com_ui_actions
  • com_ui_make_production
  • com_ui_no_versions
  • com_ui_production
  • com_ui_sr_actions_menu

⚠️ Please remove these unused keys to keep the translation files clean.

@berry-13 berry-13 added 🔨 refactor Code cleanup without new features 🎨 design UI/UX improvements labels Jan 29, 2026
@berry-13 berry-13 changed the title 🧩 refactor: reorganize prompt components 📁 refactor(Prompts): Reorganize component directory structure and enhance UI Jan 31, 2026
@berry-13 berry-13 force-pushed the refactor/prompts-components branch from f01df64 to 3a49960 Compare February 2, 2026 17:05
@github-actions

github-actions Bot commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

🚨 Unused i18next Keys Detected

The following translation keys are defined in translation.json but are not used in the codebase:

  • com_ui_actions
  • com_ui_make_production
  • com_ui_no_versions
  • com_ui_production
  • com_ui_sr_actions_menu

⚠️ Please remove these unused keys to keep the translation files clean.

@berry-13 berry-13 force-pushed the refactor/prompts-components branch from 6f71fb9 to 12c64f1 Compare February 11, 2026 16:33
@github-actions

Copy link
Copy Markdown
Contributor

🚨 Unused i18next Keys Detected

The following translation keys are defined in translation.json but are not used in the codebase:

  • com_endpoint_open_menu
  • com_ui_actions
  • com_ui_dropdown_options_count
  • com_ui_dropdown_variables_hint
  • com_ui_dropdown_variables_info
  • com_ui_editor_mode
  • com_ui_in_use
  • com_ui_latest_production_version
  • com_ui_no_versions
  • com_ui_prompt_deleted
  • com_ui_special_variables_hint
  • com_ui_special_variables_more_info
  • com_ui_sr_actions_menu
  • com_ui_used_count
  • com_ui_variables_info
  • com_ui_with_options

⚠️ Please remove these unused keys to keep the translation files clean.

@berry-13 berry-13 force-pushed the refactor/prompts-components branch from 12c64f1 to a34580a Compare February 14, 2026 15:58
@github-actions

github-actions Bot commented Feb 14, 2026

Copy link
Copy Markdown
Contributor

🚨 Unused i18next Keys Detected

The following translation keys are defined in translation.json but are not used in the codebase:

  • com_endpoint_open_menu
  • com_ui_actions
  • com_ui_dropdown_options_count
  • com_ui_dropdown_variables_hint
  • com_ui_dropdown_variables_info
  • com_ui_editor_mode
  • com_ui_in_use
  • com_ui_latest_production_version
  • com_ui_no_versions
  • com_ui_prompt_deleted
  • com_ui_special_variables_hint
  • com_ui_special_variables_more_info
  • com_ui_sr_actions_menu
  • com_ui_used_count
  • com_ui_variables_info
  • com_ui_with_options

⚠️ Please remove these unused keys to keep the translation files clean.

Copilot AI review requested due to automatic review settings February 23, 2026 00:26

Copilot AI 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.

Pull request overview

This PR refactors the Prompts UI into a more modular folder structure (buttons/dialogs/display/editor/fields/forms/layouts/lists/sidebar/utils) while also adding prompt-group usage tracking and updating prompt-group sorting to favor frequently used groups.

Changes:

  • Reorganized Prompts components into subdirectories and updated client imports/exports accordingly.
  • Added “record prompt group usage” API endpoint + client mutation and updated prompt-group sorting/indexing to prioritize numberOfGenerations.
  • Enhanced Prompts UI/UX (new create button placement, updated versions sidebar, improved variable/special-variable UI, and new/updated i18n strings).

Reviewed changes

Copilot reviewed 73 out of 81 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/data-schemas/src/schema/promptGroup.ts Updates PromptGroup compound index to support usage-based sorting/pagination.
packages/data-schemas/src/schema/prompt.ts Adds an index on author field.
packages/data-provider/src/data-service.ts Adds recordPromptGroupUsage data-service call.
packages/data-provider/src/api-endpoints.ts Adds API endpoint builder for recording prompt-group usage.
packages/client/src/components/Dropdown.tsx Minor sizing class update for icon-only dropdown trigger.
packages/api/src/prompts/format.ts Simplifies prompt group filter builder to name/category only.
client/src/routes/Layouts/DashBreadcrumb.tsx Updates Prompts component imports to new barrel exports.
client/src/locales/en/translation.json Updates/removes/adds i18n strings to match new UI and labels.
client/src/hooks/Prompts/useCategories.tsx Updates CategoryIcon import to new Prompts barrel export.
client/src/hooks/Nav/useSideNavLinks.ts Updates PromptsAccordion import to new Prompts barrel export.
client/src/data-provider/prompts.ts Adds useRecordPromptUsage mutation and updates cache on success.
client/src/components/ui/AdminSettingsDialog.tsx Refactors dialog markup/structure without changing core behavior.
client/src/components/Prompts/utils/specialVariables.ts Adds special-variable icon mapping + helper for UI.
client/src/components/Prompts/utils/index.ts Adds utils barrel exports.
client/src/components/Prompts/utils/SkeletonForm.tsx Adds skeleton UI for prompt form loading state.
client/src/components/Prompts/utils/CategoryIcon.tsx Adjusts icon sizing to be consistent (size-4).
client/src/components/Prompts/sidebar/index.ts Adds sidebar barrel exports.
client/src/components/Prompts/sidebar/PromptsAccordion.tsx Refactors accordion to use colocated sidebar components.
client/src/components/Prompts/sidebar/PanelNavigation.tsx Adds shared pagination/navigation UI for prompt group sidebar.
client/src/components/Prompts/sidebar/GroupSidePanel.tsx Adjusts layout overflow/min-width and updates imports to new structure.
client/src/components/Prompts/sidebar/FilterPrompts.tsx Adds CreatePromptButton in filter row and updates imports.
client/src/components/Prompts/lists/index.ts Adds lists barrel exports.
client/src/components/Prompts/lists/NoPromptGroup.tsx Adds “no prompt group” empty state component.
client/src/components/Prompts/lists/ListCard.tsx Improves truncation/layout and supports an optional right-side icon area.
client/src/components/Prompts/lists/List.tsx Refactors list rendering + loading skeleton layout and moves create button elsewhere.
client/src/components/Prompts/lists/DashGroupItem.tsx Adds new dashboard list item implementation with rename/delete actions.
client/src/components/Prompts/lists/ChatGroupItem.tsx Adds new chat list item implementation (preview/edit + usage recording).
client/src/components/Prompts/layouts/index.ts Adds layouts barrel export.
client/src/components/Prompts/layouts/PromptsView.tsx Updates layout sizing and imports after refactor.
client/src/components/Prompts/index.ts Rebuilds the main Prompts barrel exports across new subfolders.
client/src/components/Prompts/forms/index.ts Adds forms barrel exports.
client/src/components/Prompts/forms/VariableForm.tsx Records prompt-group usage when submitting a variable-resolved prompt.
client/src/components/Prompts/forms/PromptLabelsForm.tsx Localizes labels UI and updates styling to current theme tokens.
client/src/components/Prompts/forms/PromptForm.tsx Major refactor: header/actions split, versions sidebar redesign, and updated component wiring.
client/src/components/Prompts/forms/CreatePromptForm.tsx UI refresh for prompt creation form and updated imports.
client/src/components/Prompts/fields/index.ts Adds fields barrel exports.
client/src/components/Prompts/fields/PromptName.tsx Adds new inline-edit prompt name field with loading-aware save/cancel controls.
client/src/components/Prompts/fields/Description.tsx Adds description field component with character counter and styling updates.
client/src/components/Prompts/fields/Command.tsx Adds command field component with normalization and character counter.
client/src/components/Prompts/fields/CategorySelector.tsx Improves responsiveness (w-full on small screens).
client/src/components/Prompts/editor/index.ts Adds editor barrel exports.
client/src/components/Prompts/editor/VariablesDropdown.tsx Replaces variables dropdown with improved special-variable UX and announcements.
client/src/components/Prompts/editor/PromptEditor.tsx Adds revamped prompt editor with preview/edit toggle and better structure.
client/src/components/Prompts/editor/Markdown.tsx Moves markdown helpers into editor folder.
client/src/components/Prompts/display/index.ts Adds display barrel exports.
client/src/components/Prompts/display/PromptVersions.tsx Adds new version history UI with “latest/production” badges.
client/src/components/Prompts/display/PromptVariables.tsx Adds richer variable display (special/dropdown/text groupings).
client/src/components/Prompts/display/PromptTextCard.tsx Adds prompt text card with copy-to-clipboard feedback/toast.
client/src/components/Prompts/display/PromptDetails.tsx Adds prompt detail composition with header/text/variables/actions.
client/src/components/Prompts/display/PromptDetailHeader.tsx Adds prompt detail header showing metadata and usage count.
client/src/components/Prompts/display/PromptActions.tsx Adds “Use Prompt” action + share + usage recording flow.
client/src/components/Prompts/display/EmptyPromptPreview.tsx Adds empty preview placeholder.
client/src/components/Prompts/dialogs/index.ts Adds dialogs barrel exports.
client/src/components/Prompts/dialogs/VariableDialog.tsx Updates variable dialog styling and imports to new structure.
client/src/components/Prompts/dialogs/SharePrompt.tsx Refactors share button to be localized + tooltip + outline icon button.
client/src/components/Prompts/dialogs/PreviewPrompt.tsx Updates preview dialog to use new PromptDetails and closes on “use prompt”.
client/src/components/Prompts/dialogs/DeleteVersion.tsx Refactors delete version dialog trigger to tooltip + icon button.
client/src/components/Prompts/buttons/index.ts Adds buttons barrel exports.
client/src/components/Prompts/buttons/ManagePrompts.tsx Localizes aria-label and removes unnecessary role.
client/src/components/Prompts/buttons/CreatePromptButton.tsx Adds icon-only create prompt button with tooltip + permission gating.
client/src/components/Prompts/buttons/BackToChat.tsx Updates link target for “back to chat” to /c/new.
client/src/components/Prompts/buttons/AutoSendPrompt.tsx Refactors auto-send toggle UI to button + checkbox indicator.
client/src/components/Prompts/buttons/AlwaysMakeProd.tsx Adds always-make-production toggle component.
client/src/components/Prompts/buttons/AdvancedSwitch.tsx Adds advanced/simple mode selector as a radio UI.
client/src/components/Prompts/buttons/AdminSettings.tsx Updates AdminSettings wiring/import order and minor trigger props.
client/src/components/Prompts/VariablesDropdown.tsx Removes old variables dropdown implementation.
client/src/components/Prompts/PromptVersions.tsx Removes old versions UI implementation.
client/src/components/Prompts/PromptVariables.tsx Removes old variables UI implementation.
client/src/components/Prompts/PromptName.tsx Removes old prompt name editor implementation.
client/src/components/Prompts/PromptEditor.tsx Removes old prompt editor implementation.
client/src/components/Prompts/PromptDetails.tsx Removes old prompt details implementation.
client/src/components/Prompts/Markdown.tsx Removes old markdown helpers file (moved under editor).
client/src/components/Prompts/Groups/DashGroupItem.tsx Removes old group list item implementation (moved under lists).
client/src/components/Prompts/Groups/ChatGroupItem.tsx Removes old chat group list item implementation (moved under lists).
client/src/components/Prompts/AdvancedSwitch.tsx Removes old advanced switch implementation (moved under buttons).
client/src/components/Nav/SettingsTabs/Chat/Chat.tsx Adds AlwaysMakeProd + AutoSendPrompts toggles to chat settings.
client/src/components/Chat/Input/PromptsCommand.tsx Records prompt-group usage when selecting prompts via command UI.
client/src/Providers/PromptGroupsContext.tsx Updates CategoryIcon import to new Prompts barrel export.
api/server/routes/prompts.js Adds usage-recording endpoint, tightens query handling, and validates groupId.
api/models/Prompt.js Updates prompt-group sorting to usage-based, adds usage increment function, and refactors pagination pipeline.
.gitignore Ignores .playwright-mcp/* and CLAUDE.md.
Comments suppressed due to low confidence (1)

client/src/components/Prompts/buttons/AutoSendPrompt.tsx:35

  • aria-labelledby="auto-send-checkbox" references an id that doesn't exist in this component, which makes the markup invalid for assistive tech. Since this checkbox is aria-hidden, the simplest fix is to remove aria-labelledby; alternatively, add a real element with that id if you intend it to be announced.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread api/models/Prompt.js Outdated
Comment thread api/models/Prompt.js Outdated
Comment thread client/src/components/Prompts/editor/PromptEditor.tsx Outdated
Comment thread client/src/components/Prompts/lists/DashGroupItem.tsx Outdated

Copilot AI 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.

Pull request overview

Copilot reviewed 73 out of 81 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (1)

client/src/components/Prompts/buttons/BackToChat.tsx:19

  • The href has been changed from "/" to "/c/new". This changes the behavior of the "Back to Chat" button to always create a new conversation instead of returning to the existing chat. This could be unexpected for users who want to return to their current conversation. Consider using navigation state or a dynamic href based on whether there's an active conversation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread api/models/Prompt.js Outdated
Comment thread api/server/routes/prompts.js Outdated
Comment thread api/models/Prompt.js Outdated
Comment thread packages/data-schemas/src/schema/promptGroup.ts
Comment thread api/server/routes/prompts.js

Copilot AI 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.

Pull request overview

Copilot reviewed 77 out of 84 changed files in this pull request and generated 16 comments.

Comments suppressed due to low confidence (7)

client/src/components/Prompts/forms/PromptLabelsForm.tsx:38

  • The handleKeyPress event handler has been renamed to handleKeyDown, but the implementation still uses the deprecated onKeyPress event. This change is correct - onKeyPress is deprecated and onKeyDown should be used instead. This appears to be already fixed in the new code.
    client/src/components/Prompts/forms/PromptLabelsForm.tsx:67
  • The label elements have been changed to span elements with proper button elements for delete actions. This is a good accessibility improvement. However, the delete button is missing a visible label. While there's an aria-label, consider adding a visible tooltip or screen reader text to make the delete action more discoverable for all users.
    client/src/components/Prompts/forms/VariableForm.tsx:141
  • The VariableForm component now records prompt usage when the form is submitted. This is correct and ensures usage tracking for prompts with variables. The implementation properly checks for group._id before making the mutation call, which prevents errors when the group ID is missing.
    client/src/components/Prompts/forms/PromptForm.tsx:381
  • The debounce cleanup in the useEffect is a good practice to prevent memory leaks. However, the cleanup only happens on unmount, not when the dependencies change. If debouncedUpdateOneliner or debouncedUpdateCommand change (which they shouldn't given the empty dependency array), pending debounced calls would not be cancelled. While this is unlikely to cause issues in practice, consider moving the cleanup into the useCallback dependencies or documenting why the empty array is safe here.
    client/src/components/Prompts/forms/PromptForm.tsx:560
  • The mobile overlay now has a semi-transparent black background (bg-black/20), which improves the visual separation between the overlay panel and the content behind it. This is a good UX improvement that makes the modal nature of the panel more obvious to users.
    client/src/components/Prompts/buttons/AutoSendPrompt.tsx:38
  • The AutoSendPrompt component has been redesigned as a button with a checkbox instead of a switch with a label. This is a good UX improvement that makes the toggle more obvious and clickable. The implementation properly uses aria-pressed to indicate the toggle state, which is better for accessibility than a checkbox with tabIndex={-1}.
    client/src/components/Prompts/buttons/BackToChat.tsx:19
  • The BackToChat component's navigation URL has been changed from / to /c/new. This change should be verified to ensure it aligns with the intended user flow. If the intent is to always start a new conversation, this makes sense. However, if users might want to return to their current conversation, consider using a more dynamic approach that preserves the current conversation context.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread client/src/data-provider/prompts.ts
Comment thread client/src/components/Prompts/lists/ListCard.tsx Outdated
Comment thread packages/data-schemas/src/schema/prompt.ts
Comment thread client/src/hooks/useFocusTrap.ts Outdated
Comment thread client/src/components/Prompts/fields/PromptName.tsx
Comment thread api/server/routes/prompts.js
Comment thread client/src/components/Prompts/lists/ChatGroupItem.tsx
Comment thread client/src/components/Chat/Input/PromptsCommand.tsx
Comment thread api/models/Prompt.js Outdated
Comment thread client/src/data-provider/prompts.ts

Copilot AI 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.

Pull request overview

Copilot reviewed 81 out of 84 changed files in this pull request and generated 8 comments.

Comments suppressed due to low confidence (2)

client/src/components/Prompts/buttons/AutoSendPrompt.tsx:35

  • The AutoSendPrompt component has been refactored to use a Button with a Checkbox inside. The Checkbox has tabIndex={-1} which removes it from tab order, and the aria-label is duplicated on both the Button and Checkbox. Since the Checkbox is marked as aria-hidden="true" and pointer-events-none, it's purely decorative. However, having both aria-hidden="true" and an aria-label on the same element is contradictory - if it's hidden from assistive technology, the label won't be used. Remove the aria-label from the Checkbox since it's marked as decorative.
    client/src/components/Prompts/forms/CreatePromptForm.tsx:205
  • The Button component's aria-disabled attribute is set to !isDirty || isSubmitting || !isValid || undefined. The || undefined at the end is unnecessary because if the expression before it is falsy, it would already be false, not undefined. The aria-disabled attribute expects a string "true" or "false", not a boolean. This should be aria-disabled={(!isDirty || isSubmitting || !isValid).toString()} or simply use the disabled prop instead of aria-disabled for better semantics.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

</Link>
</Button>
}
></TooltipAnchor>

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

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

The CreatePromptButton component has an empty TooltipAnchor closing tag with ></TooltipAnchor> instead of being self-closing. While this is valid JSX, it's inconsistent with the rest of the codebase style and should be self-closing since there's no content between the tags.

Suggested change
></TooltipAnchor>
/>

Copilot uses AI. Check for mistakes.
"com_nav_2fa": "Two-Factor Authentication (2FA)",
"com_nav_account_settings": "Account Settings",
"com_nav_always_make_prod": "Always make new versions production",
"com_nav_always_make_prod": "Always make new prompt versions production",

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

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

The new translation key "com_nav_always_make_prod" changes from "Always make new versions production" to "Always make new prompt versions production". While this is more specific and clearer, any existing user documentation or help text that references the old wording should also be updated to maintain consistency.

Copilot uses AI. Check for mistakes.
Comment on lines +74 to +86
// Track loading state for detecting save completion
useEffect(() => {
wasLoadingRef.current = isLoading;
}, [isLoading]);

// Close editing when name updates after save (loading finished)
useEffect(() => {
setNewName(name);
if (wasLoadingRef.current) {
setIsEditing(false);
wasLoadingRef.current = false;
}
}, [name]);

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

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

The PromptName component uses a ref wasLoadingRef to track loading state changes, but this pattern is fragile. The component closes editing mode when wasLoadingRef.current is true and the name updates. However, if the parent component re-renders and passes the same name prop before isLoading becomes false, the edit mode won't close. Consider using a more robust pattern like comparing the previous name value with the current one in combination with loading state transitions.

Copilot uses AI. Check for mistakes.
Comment thread api/models/Prompt.js Outdated
Comment on lines 168 to 199
const { numberOfGenerations = 0, updatedAt, _id } = cursor;

if (
typeof numberOfGenerations !== 'number' ||
!Number.isFinite(numberOfGenerations) ||
typeof updatedAt !== 'string' ||
isNaN(new Date(updatedAt).getTime()) ||
typeof _id !== 'string' ||
!isValidObjectIdString(_id)
) {
logger.warn('[createAllGroupsPipeline] Invalid cursor fields, skipping cursor condition');
} else {
Object.assign(baseQuery, cursorCondition);
const cursorCondition = {
$or: [
{ numberOfGenerations: { $lt: numberOfGenerations } },
{
numberOfGenerations: numberOfGenerations,
updatedAt: { $lt: new Date(updatedAt) },
},
{
numberOfGenerations: numberOfGenerations,
updatedAt: new Date(updatedAt),
_id: { $gt: new ObjectId(_id) },
},
],
};

matchQuery =
Object.keys(baseQuery).length > 0
? { $and: [baseQuery, cursorCondition] }
: cursorCondition;
}

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

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

The cursor validation logic in the pagination system has a potential issue. When the cursor contains numberOfGenerations: 0, the fallback value assignment const { numberOfGenerations = 0, updatedAt, _id } = cursor will not override it because 0 is falsy but valid. However, the subsequent validation typeof numberOfGenerations !== 'number' || !Number.isFinite(numberOfGenerations) would correctly handle this case since 0 is a finite number. The real issue is that if numberOfGenerations is missing from the cursor entirely, it defaults to 0, but the validation doesn't check if the field was actually present in the cursor. This could lead to incorrect pagination behavior when mixing old cursors (without numberOfGenerations) with new ones.

Copilot uses AI. Check for mistakes.
.status(400)
.send({ error: 'Prompt text is required and must be a non-empty string' });
}

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

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

The prompt validation enforces type must be either "text" or "chat", but there's no validation that the type field exists at all. If prompt.type is undefined, the condition prompt.type !== 'text' && prompt.type !== 'chat' will be true and return an error, which is correct behavior. However, for clarity and better error messages, consider explicitly checking if the type field exists first and providing a more specific error message like "Prompt type is required".

Suggested change
if (typeof prompt.type !== 'string') {
return res.status(400).send({ error: 'Prompt type is required' });
}

Copilot uses AI. Check for mistakes.
Comment thread api/models/Prompt.js Outdated
Comment on lines +284 to +296
const incrementPromptGroupUsage = async (groupId) => {
const result = await PromptGroup.findByIdAndUpdate(
groupId,
{ $inc: { numberOfGenerations: 1 } },
{ new: true, select: 'numberOfGenerations' },
).lean();

if (!result) {
throw new Error('Prompt group not found');
}

return { numberOfGenerations: result.numberOfGenerations };
};

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

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

The incrementPromptGroupUsage function increments the usage counter without any concurrency control. In high-traffic scenarios with multiple simultaneous requests, MongoDB's $inc operator is atomic at the document level, so this should be safe. However, consider whether there should be a maximum limit on numberOfGenerations to prevent potential overflow or abuse scenarios.

Copilot uses AI. Check for mistakes.
);
};

const variableRegex = /{{(.*?)}}/g;

Copilot AI Feb 25, 2026

Copy link

Choose a reason for hiding this comment

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

The variable name regex pattern has been renamed from regex to variableRegex for better clarity. However, the pattern itself /{{(.*?)}}/g uses a greedy quantifier .*? which could match variables spanning multiple lines. Consider whether this is intended behavior or if the pattern should be more restrictive (e.g., /{{([^}]*?)}}/g to prevent matching across variable boundaries).

Copilot uses AI. Check for mistakes.
Comment thread client/src/components/Prompts/lists/ListCard.tsx Outdated
@berry-13 berry-13 marked this pull request as ready for review February 25, 2026 23:28
@berry-13 berry-13 added the ♿ a11y Accessibility label Feb 26, 2026
…e, and fix a11y

- Reset selectionIndex to 0 and isEditing to false when promptId
  changes, preventing out-of-bounds index when navigating between
  groups with different version counts.
- Track selectedPrompt in a ref so the auto-save effect doesn't
  fire against a stale prompt when the selection changed mid-edit.
- Stabilize useFocusTrap onEscape via useCallback to avoid
  unnecessary listener re-attachment.
- Conditionally render mobile overlay instead of always-present
  button with aria-hidden/pointer-events toggling.
…emas

The same regex helper was duplicated in api/server/routes/prompts.js
and packages/data-schemas/src/methods/prompt.ts. Moved to
packages/data-schemas/src/utils/objectId.ts and imported from both
consumers. Also removed a duplicate router.use block introduced
during the extraction.
Instead of JSON.parse(JSON.stringify(data)) which serializes the
entire paginated data structure, use targeted immutable spreads
that only copy the affected page and collection array. Returns the
original data reference unchanged when the item is not found.
…ariable

The items array containing JSX elements was rebuilt on every render.
Wrapped in useMemo keyed on usedVariables and localize. Also wrapped
handleAddVariable in useCallback and memoized usedCount to avoid
redundant array filtering.
handleSaveRename and handleDelete had updateGroup/deleteGroup mutation
objects in their useCallback dependency arrays. Since mutation objects
are new references each render, the callbacks were recreated every
render, defeating memoization. Now store mutation objects in refs and
call via ref.current in the callbacks.
The data-schema method passed the groupId string directly to
findByIdAndUpdate without validation. If called from a different
entrypoint without the route-level check, Mongoose would throw a
CastError. Now validates with isValidObjectIdString before the
DB call and throws a clean 'Invalid groupId' error.
POST /groups/:groupId/use had no rate limiting — a user could spam
it to inflate numberOfGenerations, which controls sort order for all
users. Added promptUsageLimiter (30 req/user/min) following the same
pattern as toolCallLimiter. Also handle 'Invalid groupId' error from
the data layer in the route error handler.

Copilot AI 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.

Pull request overview

Copilot reviewed 91 out of 94 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +6
import { Calendar, User, Clock, Globe, Sparkles } from 'lucide-react';
import type { specialVariables } from 'librechat-data-provider';

type SpecialVariableKey = keyof typeof specialVariables;

export const specialVariableIcons: Record<

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

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

specialVariables is imported as a type-only symbol, but it’s referenced in a typeof type query (keyof typeof specialVariables). typeof requires a value import, so this will fail TypeScript compilation. Import specialVariables as a value (non-type import) and keep the type derived from it.

Copilot uses AI. Check for mistakes.
Comment on lines +312 to +317
const PromptGroup = mongoose.models.PromptGroup as Model<IPromptGroupDocument>;
const result = await PromptGroup.findByIdAndUpdate(
groupId,
{ $inc: { numberOfGenerations: 1 } },
{ new: true, select: 'numberOfGenerations' },
).lean();

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

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

findByIdAndUpdate options don’t support select (it will be ignored). If you intend to only return numberOfGenerations, apply a projection via .select('numberOfGenerations') (or use the projection option) before .lean().

Copilot uses AI. Check for mistakes.
Comment on lines +169 to +179
export const updateFieldsInPlace = <TCollection, TData>(
data: InfiniteData<TCollection>,
updatedItem: Partial<TData>,
collectionName: string,
identifierField: keyof TData,
): InfiniteData<TCollection> => {
const { pageIndex, index } = findPage<TCollection>(data, (page) =>
page[collectionName].findIndex(
(item: TData) => item[identifierField] === updatedItem[identifierField],
),
);

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

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

updateFieldsInPlace assumes updatedItem[identifierField] is present. If it’s missing/undefined, the finder can match unintended items (or never match) depending on data shape. Add an early return when the identifier value is null/undefined to make the helper safe for wider reuse.

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +36
const ariaLabel = category
? localize('com_ui_prompt_group_button', { name, category })
: localize('com_ui_prompt_group_button_no_category', { name });

return (
<div className="relative flex w-full cursor-pointer flex-col gap-2 rounded-xl px-3 pb-4 pt-3 text-start align-top text-[15px]">
{onClick && (
<button
type="button"
className="absolute inset-0 z-0 rounded-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-ring-primary"
onClick={onClick}
aria-label={ariaLabel}
aria-describedby={`card-snippet-${name}`}
/>

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

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

aria-describedby/id values are derived from name (e.g., card-snippet-${name}), which can contain spaces/special characters and can collide across groups. This can produce invalid/duplicate IDs and break accessibility relationships. Use a stable unique identifier (e.g., group _id) or sanitize/encode the string before using it in an id.

Copilot uses AI. Check for mistakes.
berry-13 and others added 7 commits March 22, 2026 00:22
If updatedItem[identifierField] is null/undefined, findIndex could
match unintended items where that field is also undefined. Added
early return when the identifier value is nullish.
aria-describedby/id values were derived from prompt name which can
contain spaces and special characters, producing invalid HTML IDs
and potential collisions. Now uses React.useId() for guaranteed
unique, valid IDs per component instance.
Resolve merge conflict in PromptsAccordion.tsx by keeping dev's
layout/structure (AutoSendPrompt, updated classNames) with PR's
reorganized import paths.
- Match FilterPrompts first row to Memory/Bookmark pattern (items-center gap-2)
- Remove items-stretch override from PromptsAccordion
- Add missing promptUsageLimiter mock to prompts route test
- Fix #5: Gate DeletePrompt in HeaderActions behind canDelete permission
- Fix #8: BackToChat navigates to last conversation instead of /c/new
- Fix #7: Restore useLiveAnnouncer for screen reader feedback on delete/rename
- Fix #1: Use isPublic (set by API) instead of deprecated projectIds for globe icon
- Fix #4: Optimistic cache update in useRecordPromptUsage instead of full invalidation
- Fix #6: Add migration to drop superseded { createdAt, updatedAt } compound index
- Fix #9: Single-pass reduce in PromptVariables instead of triple filter
- Fix #10: Rename PromptLabelsForm internal component to avoid collision with PromptForm
- Fix #14: Remove redundant aria-label from aria-hidden Checkbox in AutoSendPrompt
- Override Dropdown trigger to size-9 (36px) to match FilterInput height
- Set CreatePromptButton to size-9 shrink-0 bg-transparent matching
  Memory/Bookmark panel button pattern
…ns PUBLIC

Folds fix from PR #11882 into the refactored codebase.

Bug A: filterAccessibleIdsBySharedLogic now accepts ownedPromptGroupIds:
- MY_PROMPTS: accessible intersect owned
- SHARED_PROMPTS: (accessible union public) minus owned
- ALL: accessible union public (deduplicated)
Legacy fallback preserved when ownedPromptGroupIds is omitted.

Bug B: getPromptGroup uses $lookup aggregation to populate productionPrompt,
fixing empty text on direct URL navigation to shared prompts.

Also adds getOwnedPromptGroupIds to data-schemas methods and passes it
from both /all and /groups route handlers.
…nceProjectId prop

- Pass canDelete to mobile HeaderActions row (was only on desktop)
- Remove instanceProjectId prop from ChatGroupItem and DashGroupItem
  since global check now uses group.isPublic
- Remove useGetStartupConfig from List.tsx (no longer needed)
…8next interpolation

- getPromptGroup and getOwnedPromptGroupIds were using Types.ObjectId
  (imported as type-only), which is erased at compile time. Use the
  runtime ObjectId from mongoose.Types (already destructured at line 20).
  This fixes the 404s in PATCH /groups/:groupId tests.
- Fix com_ui_prompt_deleted_group translation to use {{0}} (i18next
  double-brace syntax) instead of {0}.
…rovider

- Reorder new translation keys to maintain alphabetical order:
  com_ui_click_to_edit, com_ui_labels, com_ui_live, com_ui_prompt_delete_confirm,
  com_ui_prompt_deleted_group, com_ui_prompt_details, com_ui_prompt_renamed,
  com_ui_prompt_update_error, com_ui_prompt_variables_list
- Add "sideEffects": false to librechat-data-provider package.json to
  enable tree-shaking of unused exports (types, constants, pure functions)
…pattern

- Remove unnecessary wrapper div around AutoSendPrompt in PromptsAccordion,
  reducing vertical space between the toggle and the first prompt item
- Replace Memory panel's Switch toggle with Checkbox+Button pattern
  matching the prompts panel's AutoSendPrompt for visual consistency
Change ChatGroupItem margin from my-2 to mb-2 to eliminate the
doubled spacing (gap-2 from parent + top margin from first item).
Restore wrapper div around AutoSendPrompt for right-alignment.
@danny-avila danny-avila changed the title 📁 refactor(Prompts): Reorganize component directory structure and enhance UI 📁 refactor: Prompts UI Mar 22, 2026
@danny-avila

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 52e6bfa00c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread api/server/routes/prompts.js Outdated
Comment on lines +69 to +72
permissions: [Permissions.USE, Permissions.CREATE],
bodyProps: {
[Permissions.SHARE]: ['projectIds', 'removeProjectIds'],
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include SHARE in patch access check for prompt group updates

checkGlobalPromptShare is configured with permissions: [Permissions.USE, Permissions.CREATE], but checkAccess in packages/api/src/middleware/access.ts evaluates permissions.every(...) and only consults bodyProps for the permission currently being checked. Since Permissions.SHARE is not in the permissions list, the bodyProps rule for projectIds/removeProjectIds is never applied, so users with SHARE (but without CREATE) still cannot update sharing fields.

Useful? React with 👍 / 👎.

Comment on lines +35 to +40
const savedName = newName?.trim();
if (savedName && savedName !== name) {
onSave(savedName);
} else {
setIsEditing(false);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restore prompt title when rename submit is empty

When the user submits an empty or unchanged name, saveName only exits edit mode and does not restore newName. If the input was cleared, no mutation runs and the name prop does not change, so read mode renders an empty title from stale local state until a remount or external prop update. Resetting newName to name in this branch avoids the blank-title state.

Useful? React with 👍 / 👎.

…eckGlobalPromptShare

- PromptName: reset newName to name when save is cancelled due to empty
  or unchanged input, preventing blank title in read mode
- checkGlobalPromptShare: remove dead bodyProps config — Permissions.SHARE
  was not in the permissions array so the bodyProps rule was never evaluated.
  Per-resource share checks are handled by canAccessPromptGroupResource.
@danny-avila danny-avila merged commit ccd049d into dev Mar 22, 2026
13 checks passed
@danny-avila danny-avila deleted the refactor/prompts-components branch March 22, 2026 20:56
jcbartle pushed a commit to jcbartle/LibreChat that referenced this pull request May 11, 2026
* style: enhance prompts UI with new components and improved structure; add CreatePromptButton and AutoSendPrompt; refactor GroupSidePanel and PromptsAccordion

* refactor(Prompts): move button components to buttons/ subdirectory

* refactor(Prompts): move dialog components to dialogs/ subdirectory

* refactor(Prompts): move display components to display/ subdirectory

* refactor(Prompts): move editor components to editor/ subdirectory

* refactor(Prompts): move field components to fields/ subdirectory

* refactor(Prompts): move form components to forms/ subdirectory

* refactor(Prompts): move layout components to layouts/ subdirectory

* refactor(Prompts): move list components to lists/ subdirectory

* refactor(Prompts): move sidebar components to sidebar/ subdirectory

* refactor(Prompts): move utility components to utils/ subdirectory

* refactor(Prompts): update main exports and external imports

* refactor(Prompts): fix class name typo in AutoSendPrompt

* refactor(Prompts): reorganize exports and imports order across components

* refactor(Prompts): reorder exports for better organization and clarity

* refactor(Buttons): enhance prompts accessibility with aria-labels and update translations

* refactor(AdminSettings): reorganize imports and improve form structure for clarity

* refactor(Dialogs): reorganize imports for consistency and clarity across DeleteVersion, SharePrompt, and VariableDialog components

* refactor(Dialogs): enhance prompts accessibility with aria-labels

* refactor(Display): enhance prompt components and accessibility features

* refactor(.gitignore): add Playwright MCP directory

* refactor(Preview): enhance prompt components, improve layout, and add accessibility features

* refactor(Prompts): enhance variable handling, improve accessibility, and update UI components

* refactor(Prompts): enhance loading state handling and improve accessibility in PromptName component

* refactor(Prompts): streamline special variable handling, improve icon management, and enhance UI components

* refactor(Prompts): update AdvancedSwitch component to use Radio for mode selection, enhance PromptName with tooltips, and improve layout in PromptForm

* refactor(Prompts): enhance VersionCard and VersionBadge components for improved UI and accessibility, update loading state handling in VersionsPanel

* refactor(Prompts): improve layout and styling of VersionCard component for better visual alignment and clarity

* refactor(DeleteVersion): update text color for confirmation prompt in DeleteConfirmDialog

* refactor(Prompts): add configurations for always make production and auto-send prompts, update localization strings for clarity

* refactor(Prompts): enhance layout and styling in CategorySelector, CreatePromptForm, and List components for improved responsiveness and clarity

* refactor(Prompts): enhance PromptDetailHeader and ChatGroupItem components, add shared prompt indication, and remove unused PromptMetadata component

* refactor(Prompts): implement prompt group usage tracking, update sorting logic, and enhance related components

* fix(Prompts): security, performance, and pagination fixes

- Fix cursor pagination skipping/duplicating items by including
  numberOfGenerations in cursor condition to match sort order
- Close NoSQL injection vector via otherFilters rest spread in
  GET /all, GET /groups, and buildPromptGroupFilter
- Validate groupId as ObjectId before passing to query (GET /)
- Add prompt body validation in addPromptToGroup (type + text)
- Return 404 instead of 500 for missing group in POST /use
- Combine data + count into single $facet aggregation
- Add compound index {numberOfGenerations, updatedAt, _id}
- Add index on prompt.author for deleteUserPrompts
- Update useRecordPromptUsage to refresh client caches
- Replace console.error with logger.error

* refactor(PromptForm): remove console warning for unselected prompt in VersionsPanel

* refactor(Prompts): improve error handling for groupId and streamline usage tracking

* refactor(.gitignore): add CLAUDE.md to ignore list

* refactor(Prompts): streamline prompt components by removing unused variables and enhancing props structure

* refactor(Prompts): fix sort stability, keyboard handling, and remove dead code

Add _id tiebreaker to prompt group sort pipelines for deterministic
pagination ordering. Prevent default browser scroll on Space key in
PromptEditor preview mode. Remove unused blurTimeoutRef and its
onMutate callback from DashGroupItem.

* refactor(Prompts): enhance groupId validation and improve prompt group aggregation handling

* fix: aria-hidden, API fixes, accessibility improvements

* fix: ACL author filter, mobile guard, semantic HTML, and add useFocusTrap hook

- Remove author filter from patchPromptGroup so ACL-granted editors
  can update prompt groups (aligns with deletePromptGroupController)
- Add missing group guard to mobile HeaderActions in PromptForm
- Replace div with article in DashGroupItem, remove redundant
  stopPropagation and onClick on outer container
- Add useFocusTrap hook for keyboard focus management
- Add numberOfGenerations to default projection
- Deduplicate ObjectId validation, remove console.warn,
  fix aria-labelledby, localize search announcements

* refactor(Prompts): adjust UI and improve a11y

* refactor(Prompts): reorder imports for consistency and clarity

* refactor(Prompts): implement updateFieldsInPlace for efficient data updates and add related tests

* refactor(Prompts): reorder imports to include updateFieldsInPlace for better organization

* refactor(Prompts): enhance DashGroupItem with toast notifications for prompt updates and add click-to-edit functionality in PromptEditor

* style: use self-closing TooltipAnchor in CreatePromptButton

Replace ></TooltipAnchor> with /> for consistency with the rest of the Prompts directory.

* fix(i18n): replace placeholder text for com_ui_global_group translation key

The value was left as 'something needs to go here. was empty' which
would be visible to users as an aria-label in DashGroupItem.

* fix(DashGroupItem): sync rename input with group.name on external changes

nameInputValue was initialized via useState(group.name) but never
synced when group.name changed from a background refetch. Added
useEffect that updates the input when the dialog is closed.

* perf(useFocusTrap): store onEscape in ref to avoid listener churn

onEscape was in the useEffect dependency array, causing the keydown
listener to be torn down and re-attached on every render when callers
passed an inline function. Now stored in a ref so the effect only
re-runs when active or containerRef changes.

* fix(a11y): replace role=button div with layered button overlay in ListCard

The card used role='button' on a div that contained nested Button
elements — an invalid ARIA pattern. Replaced with a hidden button
at z-0 for the card action while child interactive elements sit
at z-10, eliminating nested interactive element violations.

* fix(PromptForm): reset selectionIndex on route change, guard auto-save, and fix a11y

- Reset selectionIndex to 0 and isEditing to false when promptId
  changes, preventing out-of-bounds index when navigating between
  groups with different version counts.
- Track selectedPrompt in a ref so the auto-save effect doesn't
  fire against a stale prompt when the selection changed mid-edit.
- Stabilize useFocusTrap onEscape via useCallback to avoid
  unnecessary listener re-attachment.
- Conditionally render mobile overlay instead of always-present
  button with aria-hidden/pointer-events toggling.

* refactor: extract isValidObjectIdString to shared utility in data-schemas

The same regex helper was duplicated in api/server/routes/prompts.js
and packages/data-schemas/src/methods/prompt.ts. Moved to
packages/data-schemas/src/utils/objectId.ts and imported from both
consumers. Also removed a duplicate router.use block introduced
during the extraction.

* perf(updateFieldsInPlace): replace JSON deep clone with targeted spread

Instead of JSON.parse(JSON.stringify(data)) which serializes the
entire paginated data structure, use targeted immutable spreads
that only copy the affected page and collection array. Returns the
original data reference unchanged when the item is not found.

* perf(VariablesDropdown): memoize items array and stabilize handleAddVariable

The items array containing JSX elements was rebuilt on every render.
Wrapped in useMemo keyed on usedVariables and localize. Also wrapped
handleAddVariable in useCallback and memoized usedCount to avoid
redundant array filtering.

* perf(DashGroupItem): stabilize mutation callbacks via refs

handleSaveRename and handleDelete had updateGroup/deleteGroup mutation
objects in their useCallback dependency arrays. Since mutation objects
are new references each render, the callbacks were recreated every
render, defeating memoization. Now store mutation objects in refs and
call via ref.current in the callbacks.

* fix(security): validate groupId in incrementPromptGroupUsage

The data-schema method passed the groupId string directly to
findByIdAndUpdate without validation. If called from a different
entrypoint without the route-level check, Mongoose would throw a
CastError. Now validates with isValidObjectIdString before the
DB call and throws a clean 'Invalid groupId' error.

* fix(security): add rate limiter to prompt usage tracking endpoint

POST /groups/:groupId/use had no rate limiting — a user could spam
it to inflate numberOfGenerations, which controls sort order for all
users. Added promptUsageLimiter (30 req/user/min) following the same
pattern as toolCallLimiter. Also handle 'Invalid groupId' error from
the data layer in the route error handler.

* fix(updateFieldsInPlace): guard against undefined identifier value

If updatedItem[identifierField] is null/undefined, findIndex could
match unintended items where that field is also undefined. Added
early return when the identifier value is nullish.

* fix(a11y): use React useId for stable unique IDs in ListCard

aria-describedby/id values were derived from prompt name which can
contain spaces and special characters, producing invalid HTML IDs
and potential collisions. Now uses React.useId() for guaranteed
unique, valid IDs per component instance.

* fix: Align prompts panel styling with other sidebar panels and fix test

- Match FilterPrompts first row to Memory/Bookmark pattern (items-center gap-2)
- Remove items-stretch override from PromptsAccordion
- Add missing promptUsageLimiter mock to prompts route test

* fix: Address code review findings for prompts refactor PR

- Fix danny-avila#5: Gate DeletePrompt in HeaderActions behind canDelete permission
- Fix danny-avila#8: BackToChat navigates to last conversation instead of /c/new
- Fix danny-avila#7: Restore useLiveAnnouncer for screen reader feedback on delete/rename
- Fix danny-avila#1: Use isPublic (set by API) instead of deprecated projectIds for globe icon
- Fix danny-avila#4: Optimistic cache update in useRecordPromptUsage instead of full invalidation
- Fix danny-avila#6: Add migration to drop superseded { createdAt, updatedAt } compound index
- Fix danny-avila#9: Single-pass reduce in PromptVariables instead of triple filter
- Fix danny-avila#10: Rename PromptLabelsForm internal component to avoid collision with PromptForm
- Fix danny-avila#14: Remove redundant aria-label from aria-hidden Checkbox in AutoSendPrompt

* fix: Align prompts panel filter row element sizes with other panels

- Override Dropdown trigger to size-9 (36px) to match FilterInput height
- Set CreatePromptButton to size-9 shrink-0 bg-transparent matching
  Memory/Bookmark panel button pattern

* fix(prompts): Shared Prompts filter ignores direct shares, only returns PUBLIC

Folds fix from PR danny-avila#11882 into the refactored codebase.

Bug A: filterAccessibleIdsBySharedLogic now accepts ownedPromptGroupIds:
- MY_PROMPTS: accessible intersect owned
- SHARED_PROMPTS: (accessible union public) minus owned
- ALL: accessible union public (deduplicated)
Legacy fallback preserved when ownedPromptGroupIds is omitted.

Bug B: getPromptGroup uses $lookup aggregation to populate productionPrompt,
fixing empty text on direct URL navigation to shared prompts.

Also adds getOwnedPromptGroupIds to data-schemas methods and passes it
from both /all and /groups route handlers.

* fix: Add missing canDelete to mobile HeaderActions, remove dead instanceProjectId prop

- Pass canDelete to mobile HeaderActions row (was only on desktop)
- Remove instanceProjectId prop from ChatGroupItem and DashGroupItem
  since global check now uses group.isPublic
- Remove useGetStartupConfig from List.tsx (no longer needed)

* fix: Use runtime ObjectId instead of type-only Types.ObjectId, fix i18next interpolation

- getPromptGroup and getOwnedPromptGroupIds were using Types.ObjectId
  (imported as type-only), which is erased at compile time. Use the
  runtime ObjectId from mongoose.Types (already destructured at line 20).
  This fixes the 404s in PATCH /groups/:groupId tests.
- Fix com_ui_prompt_deleted_group translation to use {{0}} (i18next
  double-brace syntax) instead of {0}.

* chore: Fix translation key ordering, add sideEffects: false to data-provider

- Reorder new translation keys to maintain alphabetical order:
  com_ui_click_to_edit, com_ui_labels, com_ui_live, com_ui_prompt_delete_confirm,
  com_ui_prompt_deleted_group, com_ui_prompt_details, com_ui_prompt_renamed,
  com_ui_prompt_update_error, com_ui_prompt_variables_list
- Add "sideEffects": false to librechat-data-provider package.json to
  enable tree-shaking of unused exports (types, constants, pure functions)

* fix: Reduce prompts panel spacing, align memory toggle with checkbox pattern

- Remove unnecessary wrapper div around AutoSendPrompt in PromptsAccordion,
  reducing vertical space between the toggle and the first prompt item
- Replace Memory panel's Switch toggle with Checkbox+Button pattern
  matching the prompts panel's AutoSendPrompt for visual consistency

* fix: Reduce gap between AutoSendPrompt and first prompt item

Change ChatGroupItem margin from my-2 to mb-2 to eliminate the
doubled spacing (gap-2 from parent + top margin from first item).
Restore wrapper div around AutoSendPrompt for right-alignment.

* fix: Restore prompt name on empty save, remove dead bodyProps from checkGlobalPromptShare

- PromptName: reset newName to name when save is cancelled due to empty
  or unchanged input, preventing blank title in read mode
- checkGlobalPromptShare: remove dead bodyProps config — Permissions.SHARE
  was not in the permissions array so the bodyProps rule was never evaluated.
  Per-resource share checks are handled by canAccessPromptGroupResource.

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

♿ a11y Accessibility 🎨 design UI/UX improvements 🔨 refactor Code cleanup without new features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants