-
-
Notifications
You must be signed in to change notification settings - Fork 9.3k
🗂️ feat: Add Private Chat Projects #13467
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
48 commits
Select commit
Hold shift + click to select a range
202bc51
feat: Add private chat projects
danny-avila 58afad4
fix: Format project files
danny-avila 4805b89
fix: Address project review findings
danny-avila 7c43b93
fix: Resolve project review follow-ups
danny-avila 77e9c0c
fix: Handle project stats and cache edge cases
danny-avila 346a131
style: align projects UI with sidebar patterns
danny-avila c66b700
fix: resolve projects UI lint issues
danny-avila 6741b70
style: Align project menus and composer
danny-avila 3d50d26
fix: Avoid project placeholder shadowing
danny-avila b1addca
fix: Handle project search and stale ids
danny-avila b34387b
fix: Polish project sidebar behavior
danny-avila c143d78
fix: Preserve new chat stream after creation
danny-avila c8299a2
fix: Stabilize project sidebar sections
danny-avila bdb979f
fix: Smooth project sidebar organization
danny-avila 4e8ad2d
fix: stabilize project chat entry
danny-avila dbfbbe4
fix: keep project workspace outside chat context
danny-avila f31b744
fix: show default model on project workspace
danny-avila a696882
fix: fallback project workspace model label
danny-avila 06a5fc3
fix: preserve project scope during draft hydration
danny-avila 6042923
fix: include route project in new chat submission
danny-avila 4dbc277
fix: persist project id in agent chat saves
danny-avila 0fafaa2
fix: refine project sidebar and creation UX
danny-avila b1342bf
fix: export chat project method types
danny-avila 4b2f785
fix: polish project landing context
danny-avila ec9f3d6
fix: refine project navigation affordances
danny-avila e25feaa
feat: rework projects UX — coexisting sidebar sections + URL-driven s…
danny-avila 7278334
chore: prune unused i18n keys; fix project chat-count pluralization
danny-avila e1e1ebb
fix: project new-chat keeps model spec; sidebar header + row polish
danny-avila e185e2c
fix: read project scope from router params; align sidebar header icons
danny-avila ed17449
fix: preserve chatProjectId through the new-chat template reduction
danny-avila dc6ca40
style: align chat-history panel top padding; improve projects page co…
danny-avila 5b9eb9f
feat: interactive project landing chip + gallery icon for all-projects
danny-avila 4a5d2b5
test: fix Conversations unit test for refactored sidebar; add project…
danny-avila 319bf15
fix: refresh project stats after project-chat activity; stabilize e2e
danny-avila 8d590b3
test: verify a project chat saves and is filed under its project (e2e)
danny-avila c5473ac
fix: address Codex review findings (project scope edge cases)
danny-avila d8686aa
fix: project stats pagination + archived-chat edge cases (data-schemas)
danny-avila 377be92
test: cover chat-less project pagination across the dated→null boundary
danny-avila c90e665
fix: validate project ownership in bulkSaveConvos
danny-avila 5b258d3
fix(projects): preserve chatProjectId on continuation, basename-safe …
danny-avila 7e7c998
fix(projects): navigate project workspace chats via useNavigateToConv…
danny-avila 90dd1af
fix(projects): include projectConversations cache when resolving dele…
danny-avila e68ce3d
fix(projects): refresh both projects when a save or bulk write moves …
danny-avila ecc36c4
Merge remote-tracking branch 'origin/dev' into projects
danny-avila 028c481
style(projects): use Folders icon for the sidebar Projects header
danny-avila 4543b08
fix(projects): require id on ProjectUser so ProjectRequest extends Ex…
danny-avila 3e929ae
style(projects): taller project chip with hover-revealed remove butto…
danny-avila 749a7d5
style(projects): show endpoint/agent icon for project workspace chat …
danny-avila File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| const express = require('express'); | ||
| const { createProjectHandlers } = require('@librechat/api'); | ||
| const requireJwtAuth = require('~/server/middleware/requireJwtAuth'); | ||
| const db = require('~/models'); | ||
|
|
||
| const router = express.Router(); | ||
| const handlers = createProjectHandlers({ | ||
| listChatProjects: db.listChatProjects, | ||
| createChatProject: db.createChatProject, | ||
| getChatProject: db.getChatProject, | ||
| updateChatProject: db.updateChatProject, | ||
| deleteChatProject: db.deleteChatProject, | ||
| assignConversationToProject: db.assignConversationToProject, | ||
| }); | ||
|
|
||
| router.use(requireJwtAuth); | ||
|
|
||
| router.get('/', handlers.listProjects); | ||
| router.post('/', handlers.createProject); | ||
| router.put('/conversations/:conversationId', handlers.assignConversationToProject); | ||
| router.get('/:projectId', handlers.getProject); | ||
| router.patch('/:projectId', handlers.updateProject); | ||
| router.delete('/:projectId', handlers.deleteProject); | ||
|
|
||
| module.exports = router; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| import { useCallback, useMemo } from 'react'; | ||
| import { useSearchParams } from 'react-router-dom'; | ||
| import { Folder, X } from 'lucide-react'; | ||
| import { ControlCombobox, TooltipAnchor } from '@librechat/client'; | ||
| import type { TChatProject } from 'librechat-data-provider'; | ||
| import type { OptionWithIcon } from '~/common'; | ||
| import { useProjectsInfiniteQuery } from '~/data-provider'; | ||
| import { useChatContext } from '~/Providers'; | ||
| import { useLocalize } from '~/hooks'; | ||
|
|
||
| /** | ||
| * Subtle project indicator shown on a project-scoped new-chat landing. | ||
| * Clicking the chip switches the project (searchable combobox); the trailing | ||
| * `×` removes the project scope. Both update the conversation draft and the | ||
| * `?projectId` search param in place, so the typed message and model are kept. | ||
| */ | ||
| export default function ProjectLandingChip({ project }: { project: TChatProject }) { | ||
| const localize = useLocalize(); | ||
| const { conversation, setConversation } = useChatContext(); | ||
| const [searchParams, setSearchParams] = useSearchParams(); | ||
|
|
||
| const { data } = useProjectsInfiniteQuery( | ||
| { sortBy: 'lastConversationAt', sortDirection: 'desc', limit: 100 }, | ||
| { staleTime: 30000 }, | ||
| ); | ||
| const projects = useMemo(() => data?.pages.flatMap((page) => page.projects) ?? [], [data?.pages]); | ||
| const items = useMemo<OptionWithIcon[]>( | ||
| () => | ||
| projects.map((item) => ({ | ||
| label: item.name, | ||
| value: item._id, | ||
| icon: <Folder className="h-4 w-4 text-text-secondary" aria-hidden="true" />, | ||
| })), | ||
| [projects], | ||
| ); | ||
|
|
||
| const applyProject = useCallback( | ||
| (projectId: string | null) => { | ||
| if (conversation) { | ||
| setConversation({ ...conversation, chatProjectId: projectId }); | ||
| } | ||
| const nextParams = new URLSearchParams(searchParams); | ||
| if (projectId) { | ||
| nextParams.set('projectId', projectId); | ||
| } else { | ||
| nextParams.delete('projectId'); | ||
| } | ||
| setSearchParams(nextParams, { replace: true }); | ||
| }, | ||
| [conversation, setConversation, searchParams, setSearchParams], | ||
| ); | ||
|
|
||
| return ( | ||
| <div className="group mb-2.5 flex items-center gap-1 px-1"> | ||
| <ControlCombobox | ||
| selectId="project-landing-select" | ||
| selectedValue={project._id} | ||
| displayValue={project.name} | ||
| items={items} | ||
| setValue={(value) => { | ||
| if (value) { | ||
| applyProject(value); | ||
| } | ||
| }} | ||
| SelectIcon={<Folder className="h-3.5 w-3.5 text-text-secondary" aria-hidden="true" />} | ||
| ariaLabel={localize('com_ui_change_project')} | ||
| searchPlaceholder={localize('com_ui_search_projects')} | ||
| isCollapsed={false} | ||
| showCarat={true} | ||
| placement="top" | ||
| containerClassName="w-auto px-0" | ||
| className="h-8 w-auto min-w-[11rem] gap-1.5 rounded-full px-2.5 text-sm font-medium text-text-secondary hover:text-text-primary" | ||
| /> | ||
| <TooltipAnchor | ||
| description={localize('com_ui_remove_from_project')} | ||
| render={ | ||
| <button | ||
| type="button" | ||
| aria-label={localize('com_ui_remove_from_project')} | ||
| onClick={() => applyProject(null)} | ||
| className="flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-text-secondary opacity-0 outline-none transition-all hover:bg-surface-hover hover:text-text-primary focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-ring-primary group-hover:opacity-100" | ||
| > | ||
| <X className="h-3.5 w-3.5" aria-hidden="true" /> | ||
| </button> | ||
| } | ||
| /> | ||
| </div> | ||
| ); | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.