mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-13 19:20:04 +00:00
♻️ refactor: restructure SPA routes to src/routes and src/router (#12542)
* 📝 docs: add SPA routes restructure design and implementation plan * ♻️ refactor: restructure SPA routes to src/routes and src/router - Move SPA page components from src/app/[variants] to src/routes/ - (main) -> Desktop pages - (mobile) -> Mobile pages - (desktop) -> Desktop-specific pages - onboarding -> Onboarding pages - share -> Share pages - Move router configurations from src/app/[variants]/router to src/router/ - desktopRouter.config.tsx - desktopRouter.config.desktop.tsx - mobileRouter.config.tsx - Keep auth pages in src/app/[variants]/(auth) for SSR - Update all import paths: - @/app/[variants]/ -> @/routes/ - Relative paths adjusted for new directory structure - Update CLAUDE.md and project-overview skill documentation * 🔧 chore: restore imports for RouteConfig and ErrorBoundary in desktopRouter.config.desktop.tsx - Reintroduced the imports for RouteConfig, ErrorBoundary, and redirectElement in the desktop router configuration file. - Ensured proper organization and functionality of the desktop routing setup. Signed-off-by: Innei <tukon479@gmail.com> * 🐛 fix: update import paths after routes restructure - Fix imports from old `src/app/[variants]/` to new `src/routes/` paths - Update Title, Sidebar, MakedownRender, McpList imports - Fix desktop-onboarding/storage import path - Run lint --fix to sort imports * 📝 docs: SPA routes convention and spa-routes skill - Add roots vs features rules to CLAUDE.md and AGENTS.md - Add .agents/skills/spa-routes for route/feature file division - Phase 1: move page route logic to src/features/Pages, thin route files Made-with: Cursor * 🌐 chore: translate non-English comments to English in memory module (#12547) Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * ♻️ refactor: move router and entries to src/spa, platform-based warmup - Move src/router and entry.*.tsx to src/spa/ - Update HTML, vite.config, and entry imports - Warmup only the entry matching current platform (web/mobile) - Update CLAUDE.md, AGENTS.md, and spa-routes skill Made-with: Cursor * 🗂️ chore: restructure SPA routes and configurations - Deleted outdated SPA routes and implementation plan documents. - Migrated SPA page components to new `src/routes/` directory. - Moved route configurations to `src/router/`. - Updated import paths across the project to reflect new structure. - Revised AI documentation to align with the updated directory layout. Signed-off-by: Innei <tukon479@gmail.com> --------- Signed-off-by: Innei <tukon479@gmail.com> Co-authored-by: LobeHub Bot <i@lobehub.com> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -101,13 +101,20 @@ lobe-chat/
|
||||
│ │ │ ├── oidc/
|
||||
│ │ │ ├── trpc/
|
||||
│ │ │ └── webapi/
|
||||
│ │ ├── [variants]/
|
||||
│ │ │ ├── (auth)/
|
||||
│ │ │ ├── (main)/
|
||||
│ │ │ ├── (mobile)/
|
||||
│ │ │ ├── onboarding/
|
||||
│ │ │ └── router/
|
||||
│ │ └── desktop/
|
||||
│ │ ├── spa/ # SPA HTML template service
|
||||
│ │ └── [variants]/
|
||||
│ │ └── (auth)/ # Auth pages (SSR required)
|
||||
│ ├── routes/ # SPA page components (Vite)
|
||||
│ │ ├── (main)/
|
||||
│ │ ├── (mobile)/
|
||||
│ │ ├── (desktop)/
|
||||
│ │ ├── onboarding/
|
||||
│ │ └── share/
|
||||
│ ├── spa/ # SPA entry points and router config
|
||||
│ │ ├── entry.web.tsx
|
||||
│ │ ├── entry.mobile.tsx
|
||||
│ │ ├── entry.desktop.tsx
|
||||
│ │ └── router/
|
||||
│ ├── business/ # Cloud-only (client/server)
|
||||
│ │ ├── client/
|
||||
│ │ ├── locales/
|
||||
@@ -155,6 +162,8 @@ lobe-chat/
|
||||
| Layer | Location |
|
||||
| ---------------- | --------------------------------------------------- |
|
||||
| UI Components | `src/components`, `src/features` |
|
||||
| SPA Pages | `src/routes/` |
|
||||
| React Router | `src/spa/router/` |
|
||||
| Global Providers | `src/layout` |
|
||||
| Zustand Stores | `src/store` |
|
||||
| Client Services | `src/services/` |
|
||||
|
||||
@@ -36,9 +36,9 @@ Hybrid routing: Next.js App Router (static pages) + React Router DOM (main SPA).
|
||||
|
||||
### Key Files
|
||||
|
||||
- Entry: `src/app/[variants]/page.tsx`
|
||||
- Desktop router: `src/app/[variants]/router/desktopRouter.config.tsx`
|
||||
- Mobile router: `src/app/[variants]/(mobile)/router/mobileRouter.config.tsx`
|
||||
- Entry: `src/spa/entry.web.tsx` (web), `src/spa/entry.mobile.tsx`, `src/spa/entry.desktop.tsx`
|
||||
- Desktop router: `src/spa/router/desktopRouter.config.tsx`
|
||||
- Mobile router: `src/spa/router/mobileRouter.config.tsx`
|
||||
- Router utilities: `src/utils/router.tsx`
|
||||
|
||||
### Router Utilities
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
name: spa-routes
|
||||
description: SPA route and feature structure. Use when adding or modifying SPA routes in src/routes, defining new route segments, or moving route logic into src/features. Covers how to keep routes thin and how to divide files between routes and features.
|
||||
---
|
||||
|
||||
# SPA Routes and Features Guide
|
||||
|
||||
SPA structure:
|
||||
|
||||
- **`src/spa/`** – Entry points (`entry.web.tsx`, `entry.mobile.tsx`, `entry.desktop.tsx`) and router config (`router/`). Router lives here to avoid confusion with `src/routes/`.
|
||||
- **`src/routes/`** – Page segments only (roots).
|
||||
- **`src/features/`** – Business logic and UI by domain.
|
||||
|
||||
This project uses a **roots vs features** split: `src/routes/` only holds page segments; business logic and UI live in `src/features/` by domain.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
- Adding a new SPA route or route segment
|
||||
- Defining or refactoring layout/page files under `src/routes/`
|
||||
- Moving route-specific components or logic into `src/features/`
|
||||
- Deciding where to put a new component (route folder vs feature folder)
|
||||
|
||||
---
|
||||
|
||||
## 1. What Belongs in `src/routes/` (roots)
|
||||
|
||||
Each route directory should contain **only**:
|
||||
|
||||
| File / folder | Purpose |
|
||||
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `_layout/index.tsx` or `layout.tsx` | Layout for this segment: wrap with `<Outlet />`, optional shell (e.g. sidebar + main). Should be thin: prefer re-exporting or composing from `@/features/*`. |
|
||||
| `index.tsx` or `page.tsx` | Page entry for this segment. Only import from features and render; no business logic. |
|
||||
| `[param]/index.tsx` (e.g. `[id]`, `[cronId]`) | Dynamic segment page. Same rule: thin, delegate to features. |
|
||||
|
||||
**Rule:** Route files should only **import and compose**. No new `features/` folders or heavy components inside `src/routes/`.
|
||||
|
||||
---
|
||||
|
||||
## 2. What Belongs in `src/features/`
|
||||
|
||||
Put **domain-oriented** UI and logic here:
|
||||
|
||||
- Layout building blocks: sidebars, headers, body panels, drawers
|
||||
- Hooks and store usage for that domain
|
||||
- Domain-specific forms, lists, modals, etc.
|
||||
|
||||
Organize by **domain** (e.g. `Pages`, `Home`, `Agent`, `PageEditor`), not by route path. One route can use several features; one feature can be used by several routes.
|
||||
|
||||
Each feature should:
|
||||
|
||||
- Live under `src/features/<FeatureName>/`
|
||||
- Export a clear public API via `index.ts` or `index.tsx`
|
||||
- Use `@/features/<FeatureName>/...` for internal imports when needed
|
||||
|
||||
---
|
||||
|
||||
## 3. How to Add a New SPA Route
|
||||
|
||||
1. **Choose the route group**
|
||||
- `(main)/` – desktop main app
|
||||
- `(mobile)/` – mobile
|
||||
- `(desktop)/` – Electron-specific
|
||||
- `onboarding/`, `share/` – special flows
|
||||
|
||||
2. **Create only segment files under `src/routes/`**
|
||||
- e.g. `src/routes/(main)/my-feature/_layout/index.tsx` and `src/routes/(main)/my-feature/index.tsx` (and optional `[id]/index.tsx`).
|
||||
|
||||
3. **Implement layout and page content in `src/features/`**
|
||||
- Create or reuse a domain (e.g. `src/features/MyFeature/`).
|
||||
- Put layout (sidebar, header, body) and page UI there; export from the feature’s `index`.
|
||||
|
||||
4. **Keep route files thin**
|
||||
- Layout: `export { default } from '@/features/MyFeature/MyLayout'` or compose a few feature components + `<Outlet />`.
|
||||
- Page: import from `@/features/MyFeature` (or a specific subpath) and render; no business logic in the route file.
|
||||
|
||||
5. **Register the route**
|
||||
- Add the segment to `src/spa/router/desktopRouter.config.tsx` (or the right router config) with `dynamicElement` / `dynamicLayout` pointing at the new route paths (e.g. `@/routes/(main)/my-feature`).
|
||||
|
||||
---
|
||||
|
||||
## 4. How to Divide Files (route vs feature)
|
||||
|
||||
| Question | Put in `src/routes/` | Put in `src/features/` |
|
||||
| -------------------------------------------------------- | -------------------------------------------------------- | ---------------------------- |
|
||||
| Is it the route’s layout wrapper or page entry? | Yes – `_layout/index.tsx`, `index.tsx`, `[id]/index.tsx` | No |
|
||||
| Does it contain business logic or non-trivial UI? | No | Yes – under the right domain |
|
||||
| Is it a reusable layout piece (sidebar, header, body)? | No | Yes |
|
||||
| Is it a hook, store usage, or domain logic? | No | Yes |
|
||||
| Is it only re-exporting or composing feature components? | Yes | No |
|
||||
|
||||
**Examples**
|
||||
|
||||
- **Route (thin):**\
|
||||
`src/routes/(main)/page/_layout/index.tsx` → `export { default } from '@/features/Pages/PageLayout'`
|
||||
- **Feature (real implementation):**\
|
||||
`src/features/Pages/PageLayout/` → Sidebar, DataSync, Body, Header, styles, etc.
|
||||
- **Route (thin):**\
|
||||
`src/routes/(main)/page/index.tsx` → Import `PageTitle`, `PageExplorerPlaceholder` from `@/features/Pages` and `@/features/PageExplorer`; render with `<PageTitle />` and placeholder.
|
||||
- **Feature:**\
|
||||
Page list, actions, drawers, and hooks live under `src/features/Pages/`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Progressive Migration (existing code)
|
||||
|
||||
We are migrating existing routes to this structure step by step:
|
||||
|
||||
- **Phase 1 (done):** `/page` route – segment files in `src/routes/(main)/page/`, implementation in `src/features/Pages/`.
|
||||
- **Later phases:** home, settings, agent/group, community/resource/memory, mobile/share/onboarding.
|
||||
|
||||
When touching an old route that still has logic or `features/` inside `src/routes/`:
|
||||
|
||||
1. Prefer adding **new** code in `src/features/<Domain>/` and importing from routes.
|
||||
2. For larger refactors, move existing route-only logic into the right feature and then thin out the route files (re-export or compose from features).
|
||||
3. Use `git mv` when moving files so history is preserved.
|
||||
|
||||
---
|
||||
|
||||
## 6. Reference Structure (after Phase 1)
|
||||
|
||||
**Route (thin):**
|
||||
|
||||
```
|
||||
src/routes/(main)/page/
|
||||
├── _layout/index.tsx → re-export or compose from @/features/Pages/PageLayout
|
||||
├── index.tsx → import from @/features/Pages, @/features/PageExplorer
|
||||
└── [id]/index.tsx → import from @/features/Pages, @/features/PageExplorer
|
||||
```
|
||||
|
||||
**Feature (implementation):**
|
||||
|
||||
```
|
||||
src/features/Pages/
|
||||
├── index.ts → export PageLayout, PageTitle
|
||||
├── PageTitle.tsx
|
||||
└── PageLayout/
|
||||
├── index.tsx → Sidebar + Outlet + DataSync
|
||||
├── DataSync.tsx
|
||||
├── Sidebar.tsx
|
||||
├── style.ts
|
||||
├── Body/ → list, actions, drawer, etc.
|
||||
└── Header/ → breadcrumb, add button, etc.
|
||||
```
|
||||
|
||||
Router config continues to point at **route** paths (e.g. `@/routes/(main)/page`, `@/routes/(main)/page/_layout`); route files then delegate to features.
|
||||
@@ -26,6 +26,9 @@ lobe-chat/
|
||||
│ └── ...
|
||||
├── src/
|
||||
│ ├── app/ # Next.js app router
|
||||
│ ├── spa/ # SPA entry points (entry.*.tsx) and router config
|
||||
│ ├── routes/ # SPA page components (roots)
|
||||
│ ├── features/ # Business components by domain
|
||||
│ ├── store/ # Zustand stores
|
||||
│ ├── services/ # Client services
|
||||
│ ├── server/ # Server services and routers
|
||||
@@ -87,19 +90,26 @@ cd packages/[package-name] && bunx vitest run --silent='passed-only' '[file-path
|
||||
|
||||
Follow [Linear rules in CLAUDE.md](CLAUDE.md#linear-issue-management-ignore-if-not-installed-linear-mcp) when working with Linear issues.
|
||||
|
||||
## SPA Routes and Features
|
||||
|
||||
- **`src/routes/`** holds only page segments (layout + page entry files). Keep route files thin; they should import from `@/features/*` and compose.
|
||||
- **`src/features/`** holds business components by domain. Put layout pieces, hooks, and domain UI here.
|
||||
- See [CLAUDE.md – SPA Routes and Features](CLAUDE.md#spa-routes-and-features) and the **spa-routes** skill for how to add new routes and how to split files.
|
||||
|
||||
## Skills (Auto-loaded)
|
||||
|
||||
All AI development skills are available in `.agents/skills/` directory:
|
||||
|
||||
| Category | Skills |
|
||||
| ----------- | ------------------------------------------ |
|
||||
| Frontend | `react`, `typescript`, `i18n`, `microcopy` |
|
||||
| State | `zustand` |
|
||||
| Backend | `drizzle` |
|
||||
| Desktop | `desktop` |
|
||||
| Testing | `testing` |
|
||||
| UI | `modal`, `hotkey`, `recent-data` |
|
||||
| Config | `add-provider-doc`, `add-setting-env` |
|
||||
| Workflow | `linear`, `debug` |
|
||||
| Performance | `vercel-react-best-practices` |
|
||||
| Overview | `project-overview` |
|
||||
| Category | Skills |
|
||||
| ------------ | ------------------------------------------ |
|
||||
| Frontend | `react`, `typescript`, `i18n`, `microcopy` |
|
||||
| State | `zustand` |
|
||||
| Backend | `drizzle` |
|
||||
| Desktop | `desktop` |
|
||||
| Testing | `testing` |
|
||||
| UI | `modal`, `hotkey`, `recent-data` |
|
||||
| Config | `add-provider-doc`, `add-setting-env` |
|
||||
| Workflow | `linear`, `debug` |
|
||||
| Architecture | `spa-routes` |
|
||||
| Performance | `vercel-react-best-practices` |
|
||||
| Overview | `project-overview` |
|
||||
|
||||
@@ -21,7 +21,21 @@ lobe-chat/
|
||||
│ ├── agent-runtime/ # Agent runtime
|
||||
│ └── ...
|
||||
├── src/
|
||||
│ ├── app/ # Next.js app router
|
||||
│ ├── app/ # Next.js App Router (backend API + auth)
|
||||
│ │ ├── (backend)/ # API routes (trpc, webapi, etc.)
|
||||
│ │ ├── spa/ # SPA HTML template service
|
||||
│ │ └── [variants]/(auth)/ # Auth pages (SSR required)
|
||||
│ ├── routes/ # SPA page components (Vite)
|
||||
│ │ ├── (main)/ # Desktop pages
|
||||
│ │ ├── (mobile)/ # Mobile pages
|
||||
│ │ ├── (desktop)/ # Desktop-specific pages
|
||||
│ │ ├── onboarding/ # Onboarding pages
|
||||
│ │ └── share/ # Share pages
|
||||
│ ├── spa/ # SPA entry points and router config
|
||||
│ │ ├── entry.web.tsx # Web entry
|
||||
│ │ ├── entry.mobile.tsx
|
||||
│ │ ├── entry.desktop.tsx
|
||||
│ │ └── router/ # React Router configuration
|
||||
│ ├── store/ # Zustand stores
|
||||
│ ├── services/ # Client services
|
||||
│ ├── server/ # Server services and routers
|
||||
@@ -29,6 +43,26 @@ lobe-chat/
|
||||
└── e2e/ # E2E tests (Cucumber + Playwright)
|
||||
```
|
||||
|
||||
## SPA Routes and Features
|
||||
|
||||
SPA-related code is grouped under `src/spa/` (entries + router) and `src/routes/` (page segments). We use a **roots vs features** split: route trees only hold page segments; business logic and UI live in features.
|
||||
|
||||
- **`src/spa/`** – SPA entry points (`entry.web.tsx`, `entry.mobile.tsx`, `entry.desktop.tsx`) and React Router config (`router/`). Keeps router config next to entries to avoid confusion with `src/routes/`.
|
||||
|
||||
- **`src/routes/` (roots)**\
|
||||
Only page-segment files: `_layout/index.tsx`, `index.tsx` (or `page.tsx`), and dynamic segments like `[id]/index.tsx`. Keep these **thin**: they should only import from `@/features/*` and compose layout/page, with no business logic or heavy UI.
|
||||
|
||||
- **`src/features/`**\
|
||||
Business components by **domain** (e.g. `Pages`, `PageEditor`, `Home`). Put layout chunks (sidebar, header, body), hooks, and domain-specific UI here. Each feature exposes an `index.ts` (or `index.tsx`) with clear exports.
|
||||
|
||||
When adding or changing SPA routes:
|
||||
|
||||
1. In `src/routes/`, add only the route segment files (layout + page) that delegate to features.
|
||||
2. Implement layout and page content under `src/features/<Domain>/` and export from there.
|
||||
3. In route files, use `import { X } from '@/features/<Domain>'` (or `import Y from '@/features/<Domain>/...'`). Do not add new `features/` folders inside `src/routes/`.
|
||||
|
||||
See the **spa-routes** skill (`.agents/skills/spa-routes/SKILL.md`) for the full convention and file-division rules.
|
||||
|
||||
## Development
|
||||
|
||||
### Starting the Dev Environment
|
||||
|
||||
@@ -85,6 +85,6 @@
|
||||
<script>
|
||||
window.__SERVER_CONFIG__ = undefined;
|
||||
</script>
|
||||
<script type="module" src="../../src/entry.desktop.tsx"></script>
|
||||
<script type="module" src="../../src/spa/entry.desktop.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+1
-1
@@ -136,6 +136,6 @@
|
||||
<div id="root" style="height: 100%"></div>
|
||||
|
||||
<!--ANALYTICS_SCRIPTS-->
|
||||
<script type="module" src="/src/entry.web.tsx"></script>
|
||||
<script type="module" src="/src/spa/entry.web.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+1
-1
@@ -63,6 +63,6 @@
|
||||
<div id="root" style="height: 100%"></div>
|
||||
|
||||
<!--ANALYTICS_SCRIPTS-->
|
||||
<script type="module" src="/src/entry.mobile.tsx"></script>
|
||||
<script type="module" src="/src/spa/entry.mobile.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
// Re-export from chat version to avoid code duplication
|
||||
export { default } from '@/app/[variants]/(main)/agent/features/Conversation/AgentWelcome/ToolAuthAlert';
|
||||
@@ -1,3 +0,0 @@
|
||||
import Loading from '@/components/Loading/BrandTextLoading';
|
||||
|
||||
export default () => <Loading debugId="Image Page" />;
|
||||
@@ -1,98 +0,0 @@
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { Loader2Icon } from 'lucide-react';
|
||||
import { type CSSProperties } from 'react';
|
||||
import React, { memo, useCallback, useMemo } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import RepoIcon from '@/components/LibIcon';
|
||||
import NavItem from '@/features/NavPanel/components/NavItem';
|
||||
import { useKnowledgeBaseStore } from '@/store/library';
|
||||
|
||||
import Actions from './Actions';
|
||||
import Editing from './Editing';
|
||||
import { useDropdownMenu } from './useDropdownMenu';
|
||||
|
||||
interface KnowledgeBaseItemProps {
|
||||
active?: boolean;
|
||||
className?: string;
|
||||
description?: string | null;
|
||||
id: string;
|
||||
name: string;
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
const KnowledgeBaseItem = memo<KnowledgeBaseItemProps>(({ id, name, description, active, style, className }) => {
|
||||
const setLibraryId = useResourceManagerStore((s) => s.setLibraryId);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [editing, isLoading] = useKnowledgeBaseStore((s) => [
|
||||
s.knowledgeBaseRenamingId === id,
|
||||
s.knowledgeBaseLoadingIds.includes(id),
|
||||
]);
|
||||
|
||||
const toggleEditing = useCallback(
|
||||
(visible?: boolean) => {
|
||||
useKnowledgeBaseStore.setState(
|
||||
{ knowledgeBaseRenamingId: visible ? id : null },
|
||||
false,
|
||||
'toggleEditing',
|
||||
);
|
||||
},
|
||||
[id],
|
||||
);
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (!editing) {
|
||||
navigate(`/resource/library/${id}`);
|
||||
setLibraryId(id);
|
||||
}
|
||||
}, [editing, navigate, id]);
|
||||
|
||||
const handleDoubleClick = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
if (e.altKey) {
|
||||
toggleEditing(true);
|
||||
}
|
||||
},
|
||||
[toggleEditing],
|
||||
);
|
||||
|
||||
// Icon (show loader when updating)
|
||||
const icon = useMemo(() => {
|
||||
if (isLoading) {
|
||||
return <Icon spin color={cssVar.colorTextDescription} icon={Loader2Icon} size={18} />;
|
||||
}
|
||||
return <RepoIcon size={18} />;
|
||||
}, [isLoading]);
|
||||
|
||||
const dropdownMenu = useDropdownMenu({
|
||||
description,
|
||||
id,
|
||||
name,
|
||||
toggleEditing,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<NavItem
|
||||
actions={<Actions dropdownMenu={dropdownMenu} />}
|
||||
active={active}
|
||||
className={className}
|
||||
contextMenuItems={dropdownMenu}
|
||||
disabled={editing}
|
||||
icon={icon}
|
||||
key={id}
|
||||
loading={isLoading}
|
||||
style={style}
|
||||
title={name}
|
||||
onClick={handleClick}
|
||||
onDoubleClick={handleDoubleClick}
|
||||
/>
|
||||
<Editing id={id} name={name} toggleEditing={toggleEditing} />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default KnowledgeBaseItem;
|
||||
@@ -7,8 +7,7 @@ import { Fragment, isValidElement, memo } from 'react';
|
||||
|
||||
export const toolsListStyles = createStaticStyles(({ css }) => ({
|
||||
groupLabel: css`
|
||||
padding-block-start: 12px;
|
||||
padding-block-end: 4px;
|
||||
padding-block: 12px 4px;
|
||||
padding-inline: 12px;
|
||||
`,
|
||||
item: css`
|
||||
|
||||
@@ -4,12 +4,12 @@ import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import useSWR from 'swr';
|
||||
|
||||
import { useCreateMenuItems } from '@/app/[variants]/(main)/home/_layout/hooks';
|
||||
import { isDesktop } from '@/const/version';
|
||||
import { type SearchResult } from '@/database/repositories/search';
|
||||
import { useCreateNewModal } from '@/features/LibraryModal';
|
||||
import { useGroupWizard } from '@/layout/GlobalProvider/GroupWizardProvider';
|
||||
import { lambdaClient } from '@/libs/trpc/client';
|
||||
import { useCreateMenuItems } from '@/routes/(main)/home/_layout/hooks';
|
||||
import { electronSystemService } from '@/services/electron/system';
|
||||
import { useAgentStore } from '@/store/agent';
|
||||
import { builtinAgentSelectors } from '@/store/agent/selectors/builtinAgentSelectors';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useWatchBroadcast } from '@lobechat/electron-client-ipc';
|
||||
import { useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useCreateMenuItems } from '@/app/[variants]/(main)/home/_layout/hooks/useCreateMenuItems';
|
||||
import { useCreateMenuItems } from '@/routes/(main)/home/_layout/hooks/useCreateMenuItems';
|
||||
import { useAgentStore } from '@/store/agent';
|
||||
import { builtinAgentSelectors } from '@/store/agent/selectors';
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { AlertCircle, LogIn } from 'lucide-react';
|
||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { getDesktopOnboardingCompleted } from '@/app/[variants]/(desktop)/desktop-onboarding/storage';
|
||||
import { getDesktopOnboardingCompleted } from '@/routes/(desktop)/desktop-onboarding/storage';
|
||||
import { useElectronStore } from '@/store/electron';
|
||||
|
||||
interface AuthRequiredModalContentProps {
|
||||
|
||||
@@ -3,8 +3,8 @@ import { Drawer } from 'antd';
|
||||
import { createStaticStyles, cssVar } from 'antd-style';
|
||||
import { Suspense, useCallback } from 'react';
|
||||
|
||||
import LoginStep from '@/app/[variants]/(desktop)/desktop-onboarding/features/LoginStep';
|
||||
import { BrandTextLoading } from '@/components/Loading';
|
||||
import LoginStep from '@/routes/(desktop)/desktop-onboarding/features/LoginStep';
|
||||
import { useElectronStore } from '@/store/electron';
|
||||
import { isMacOS } from '@/utils/platform';
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import { Flexbox } from '@lobehub/ui';
|
||||
import { type ReactNode } from 'react';
|
||||
import { memo } from 'react';
|
||||
|
||||
import { type TitleProps } from '../../app/[variants]/(main)/community/features/Title';
|
||||
import Title from '../../app/[variants]/(main)/community/features/Title';
|
||||
import { type TitleProps } from '@/routes/(main)/community/features/Title';
|
||||
import Title from '@/routes/(main)/community/features/Title';
|
||||
|
||||
export type CollapseItemType = {
|
||||
children: ReactNode;
|
||||
|
||||
@@ -28,9 +28,9 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
import Descriptions from '@/components/Descriptions';
|
||||
import InlineTable from '@/components/InlineTable';
|
||||
import Title from '@/routes/(main)/community/features/Title';
|
||||
import { markdownToTxt } from '@/utils/markdownToTxt';
|
||||
|
||||
import Title from '../../../app/[variants]/(main)/community/features/Title';
|
||||
import InstallationIcon from '../../../components/MCPDepsIcon';
|
||||
import CollapseDesc from '../CollapseDesc';
|
||||
import CollapseLayout from '../CollapseLayout';
|
||||
|
||||
@@ -3,9 +3,10 @@ import qs from 'query-string';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import MarkdownRender from '../../../app/[variants]/(main)/community/(detail)/features/MakedownRender';
|
||||
import McpList from '../../../app/[variants]/(main)/community/(list)/mcp/features/List';
|
||||
import Title from '../../../app/[variants]/(main)/community/features/Title';
|
||||
import MarkdownRender from '@/routes/(main)/community/(detail)/features/MakedownRender';
|
||||
import McpList from '@/routes/(main)/community/(list)/mcp/features/List';
|
||||
import Title from '@/routes/(main)/community/features/Title';
|
||||
|
||||
import { useDetailContext } from '../DetailProvider';
|
||||
import TagList from './TagList';
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ import { type ReactNode } from 'react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import Title from '../../../app/[variants]/(main)/community/features/Title';
|
||||
import Title from '@/routes/(main)/community/features/Title';
|
||||
|
||||
import { ModeType } from './types';
|
||||
|
||||
interface BlockProps {
|
||||
|
||||
@@ -5,9 +5,9 @@ import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import InlineTable from '@/components/InlineTable';
|
||||
import Title from '@/routes/(main)/community/features/Title';
|
||||
import { markdownToTxt } from '@/utils/markdownToTxt';
|
||||
|
||||
import Title from '../../../app/[variants]/(main)/community/features/Title';
|
||||
import CollapseDesc from '../CollapseDesc';
|
||||
import CollapseLayout from '../CollapseLayout';
|
||||
import { useDetailContext } from '../DetailProvider';
|
||||
|
||||
@@ -5,9 +5,9 @@ import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import InlineTable from '@/components/InlineTable';
|
||||
import Title from '@/routes/(main)/community/features/Title';
|
||||
import { markdownToTxt } from '@/utils/markdownToTxt';
|
||||
|
||||
import Title from '../../../app/[variants]/(main)/community/features/Title';
|
||||
import CollapseDesc from '../CollapseDesc';
|
||||
import CollapseLayout from '../CollapseLayout';
|
||||
import { useDetailContext } from '../DetailProvider';
|
||||
|
||||
@@ -4,7 +4,7 @@ import { BanIcon, CircleCheckBigIcon, CircleDashedIcon } from 'lucide-react';
|
||||
import { type ReactNode } from 'react';
|
||||
import { memo } from 'react';
|
||||
|
||||
import Title from '../../../app/[variants]/(main)/community/features/Title';
|
||||
import Title from '@/routes/(main)/community/features/Title';
|
||||
|
||||
export interface ScoreItemProps {
|
||||
check: boolean;
|
||||
|
||||
@@ -9,8 +9,8 @@ import {
|
||||
sortItemsByPriority,
|
||||
} from '@/features/MCP/calculateScore';
|
||||
import { useScoreList } from '@/features/MCP/useScoreList';
|
||||
import Title from '@/routes/(main)/community/features/Title';
|
||||
|
||||
import Title from '../../../app/[variants]/(main)/community/features/Title';
|
||||
import { useDetailContext } from '../DetailProvider';
|
||||
import GithubBadge from './GithubBadge';
|
||||
import ScoreList from './ScoreList';
|
||||
|
||||
@@ -2,8 +2,8 @@ import { Flexbox, ScrollShadow, TooltipGroup } from '@lobehub/ui';
|
||||
import { type ReactNode } from 'react';
|
||||
import { memo, Suspense } from 'react';
|
||||
|
||||
import Footer from '@/app/[variants]/(main)/home/_layout/Footer';
|
||||
import SkeletonList, { SkeletonItem } from '@/features/NavPanel/components/SkeletonList';
|
||||
import Footer from '@/routes/(main)/home/_layout/Footer';
|
||||
|
||||
interface SidebarLayoutProps {
|
||||
body?: ReactNode;
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
import { DraggablePanel, Freeze } from '@lobehub/ui';
|
||||
import { createStaticStyles, cssVar } from 'antd-style';
|
||||
import { AnimatePresence, motion, useIsPresent } from 'motion/react';
|
||||
import { type ReactNode } from 'react';
|
||||
import { type ReactNode } from 'react';
|
||||
import { memo, useLayoutEffect, useMemo, useRef } from 'react';
|
||||
|
||||
import { USER_DROPDOWN_ICON_ID } from '@/app/[variants]/(main)/home/_layout/Header/components/User';
|
||||
import { isDesktop } from '@/const/version';
|
||||
import { TOGGLE_BUTTON_ID } from '@/features/NavPanel/ToggleLeftPanelButton';
|
||||
import { USER_DROPDOWN_ICON_ID } from '@/routes/(main)/home/_layout/Header/components/User';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { systemStatusSelectors } from '@/store/global/selectors';
|
||||
import { useUserStore } from '@/store/user';
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
import { type PropsWithChildren, type ReactNode } from 'react';
|
||||
import { memo, useLayoutEffect, useSyncExternalStore } from 'react';
|
||||
|
||||
import Sidebar from '../../app/[variants]/(main)/home/_layout/Sidebar';
|
||||
import Sidebar from '@/routes/(main)/home/_layout/Sidebar';
|
||||
|
||||
import { NavPanelDraggable } from './components/NavPanelDraggable';
|
||||
|
||||
export const NAV_PANEL_RIGHT_DRAWER_ID = 'nav-panel-drawer';
|
||||
|
||||
@@ -2,8 +2,8 @@ import { type GroupMemberAvatar } from '@lobechat/types';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import AgentAvatar from '@/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentItem/Avatar';
|
||||
import NavItem from '@/features/NavPanel/components/NavItem';
|
||||
import AgentAvatar from '@/routes/(main)/home/_layout/Body/Agent/List/AgentItem/Avatar';
|
||||
|
||||
interface AgentItemProps {
|
||||
active: boolean;
|
||||
|
||||
@@ -4,10 +4,10 @@ import { ChevronsUpDownIcon } from 'lucide-react';
|
||||
import { memo, Suspense, useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import AgentAvatar from '@/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentItem/Avatar';
|
||||
import { AgentModalProvider } from '@/app/[variants]/(main)/home/_layout/Body/Agent/ModalProvider';
|
||||
import SkeletonList from '@/features/NavPanel/components/SkeletonList';
|
||||
import { useFetchAgentList } from '@/hooks/useFetchAgentList';
|
||||
import AgentAvatar from '@/routes/(main)/home/_layout/Body/Agent/List/AgentItem/Avatar';
|
||||
import { AgentModalProvider } from '@/routes/(main)/home/_layout/Body/Agent/ModalProvider';
|
||||
import { useAgentStore } from '@/store/agent';
|
||||
import { useHomeStore } from '@/store/home';
|
||||
import { homeAgentListSelectors } from '@/store/home/selectors';
|
||||
|
||||
@@ -12,7 +12,7 @@ interface PageExplorerProps {
|
||||
/**
|
||||
* Dedicated for the /page route
|
||||
*
|
||||
* Work together with a sidebar src/app/[variants]/(main)/page/_layout/Body/index.tsx
|
||||
* Work together with a sidebar @/features/Pages/PageLayout/Body
|
||||
*/
|
||||
const PageExplorer = memo<PageExplorerProps>(({ pageId }) => {
|
||||
const updatePageOptimistically = usePageStore((s) => s.updatePageOptimistically);
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import { Accordion, AccordionItem, ContextMenuTrigger, Flexbox, Text } from '@lobehub/ui';
|
||||
import React, { memo,Suspense } from 'react';
|
||||
import React, { memo, Suspense } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import SkeletonList from '@/features/NavPanel/components/SkeletonList';
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default as PageLayout } from './PageLayout';
|
||||
export { default as PageTitle } from './PageTitle';
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { memo } from 'react';
|
||||
|
||||
import FileDetailComponent from '@/app/[variants]/(main)/resource/features/FileDetail';
|
||||
import FileDetailComponent from '@/routes/(main)/resource/features/FileDetail';
|
||||
import { fileManagerSelectors, useFileStore } from '@/store/file';
|
||||
|
||||
interface FileDetailProps {
|
||||
|
||||
@@ -8,11 +8,11 @@ import { ArrowLeftIcon, DownloadIcon, InfoIcon } from 'lucide-react';
|
||||
import { memo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import FileDetailComponent from '@/app/[variants]/(main)/resource/features/FileDetail';
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import Loading from '@/components/Loading/BrandTextLoading';
|
||||
import NavHeader from '@/features/NavHeader';
|
||||
import PageAgentProvider from '@/features/PageEditor/PageAgentProvider';
|
||||
import FileDetailComponent from '@/routes/(main)/resource/features/FileDetail';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { useAgentStore } from '@/store/agent';
|
||||
import { builtinAgentSelectors } from '@/store/agent/selectors';
|
||||
import { fileManagerSelectors, useFileStore } from '@/store/file';
|
||||
@@ -39,7 +39,12 @@ const FileEditorCanvas = memo<FileEditorProps>(({ onBack }) => {
|
||||
<Flexbox flex={1} height={'100%'}>
|
||||
<NavHeader
|
||||
left={
|
||||
<Flexbox horizontal align={'center'} gap={12} style={{ minHeight: 32, minWidth: 0, overflow: 'hidden' }}>
|
||||
<Flexbox
|
||||
horizontal
|
||||
align={'center'}
|
||||
gap={12}
|
||||
style={{ minHeight: 32, minWidth: 0, overflow: 'hidden' }}
|
||||
>
|
||||
<ActionIcon icon={ArrowLeftIcon} title={t('back')} onClick={onBack} />
|
||||
<span
|
||||
title={fileDetail?.name}
|
||||
|
||||
@@ -4,8 +4,8 @@ import { createStaticStyles, cssVar } from 'antd-style';
|
||||
import { ArrowUpIcon, PlusIcon } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { useCreateNewModal } from '@/features/LibraryModal';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { useFileStore } from '@/store/file';
|
||||
|
||||
const ICON_SIZE = 80;
|
||||
|
||||
@@ -4,8 +4,8 @@ import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { useFolderPath } from '@/app/[variants]/(main)/resource/features/hooks/useFolderPath';
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { useFolderPath } from '@/routes/(main)/resource/features/hooks/useFolderPath';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { useFileStore } from '@/store/file';
|
||||
import { knowledgeBaseSelectors, useKnowledgeBaseStore } from '@/store/library';
|
||||
import { FilesTabs } from '@/types/files';
|
||||
|
||||
@@ -7,7 +7,7 @@ import { SearchIcon, XIcon } from 'lucide-react';
|
||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
|
||||
const SearchInput = memo(() => {
|
||||
const { t } = useTranslation('components');
|
||||
|
||||
@@ -7,8 +7,8 @@ import { BookMinusIcon, FileBoxIcon, Trash2Icon } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import NavHeader from '@/features/NavHeader';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { FilesTabs } from '@/types/files';
|
||||
|
||||
import AddButton from '../../Header/AddButton';
|
||||
|
||||
@@ -18,15 +18,15 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
|
||||
import FileIcon from '@/components/FileIcon';
|
||||
import { clearTreeFolderCache } from '@/features/ResourceManager/components/LibraryHierarchy';
|
||||
import { PAGE_FILE_TYPE } from '@/features/ResourceManager/constants';
|
||||
import {
|
||||
getTransparentDragImage,
|
||||
useDragActive,
|
||||
useDragState,
|
||||
} from '@/app/[variants]/(main)/resource/features/DndContextWrapper';
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import FileIcon from '@/components/FileIcon';
|
||||
import { clearTreeFolderCache } from '@/features/ResourceManager/components/LibraryHierarchy';
|
||||
import { PAGE_FILE_TYPE } from '@/features/ResourceManager/constants';
|
||||
} from '@/routes/(main)/resource/features/DndContextWrapper';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { fileManagerSelectors, useFileStore } from '@/store/file';
|
||||
import { type FileListItem as FileListItemType } from '@/types/files';
|
||||
import { formatSize } from '@/utils/format';
|
||||
|
||||
@@ -9,13 +9,13 @@ import { useTranslation } from 'react-i18next';
|
||||
import { type VirtuosoHandle } from 'react-virtuoso';
|
||||
import { Virtuoso } from 'react-virtuoso';
|
||||
|
||||
import { useDragActive } from '@/app/[variants]/(main)/resource/features/DndContextWrapper';
|
||||
import { useFolderPath } from '@/app/[variants]/(main)/resource/features/hooks/useFolderPath';
|
||||
import { useDragActive } from '@/routes/(main)/resource/features/DndContextWrapper';
|
||||
import { useFolderPath } from '@/routes/(main)/resource/features/hooks/useFolderPath';
|
||||
import {
|
||||
useResourceManagerFetchFolderBreadcrumb,
|
||||
useResourceManagerStore,
|
||||
} from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { sortFileList } from '@/app/[variants]/(main)/resource/features/store/selectors';
|
||||
} from '@/routes/(main)/resource/features/store';
|
||||
import { sortFileList } from '@/routes/(main)/resource/features/store/selectors';
|
||||
import { useFileStore } from '@/store/file';
|
||||
import { useFetchResources } from '@/store/file/slices/resource/hooks';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
getTransparentDragImage,
|
||||
useDragActive,
|
||||
useDragState,
|
||||
} from '@/app/[variants]/(main)/resource/features/DndContextWrapper';
|
||||
} from '@/routes/(main)/resource/features/DndContextWrapper';
|
||||
import { documentService } from '@/services/document';
|
||||
import { type FileListItem } from '@/types/files';
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import { type UIEvent } from 'react';
|
||||
import { memo, useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { sortFileList } from '@/app/[variants]/(main)/resource/features/store/selectors';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { sortFileList } from '@/routes/(main)/resource/features/store/selectors';
|
||||
import { useFileStore } from '@/store/file';
|
||||
import { useFetchResources } from '@/store/file/slices/resource/hooks';
|
||||
import { type FileListItem } from '@/types/files';
|
||||
|
||||
@@ -8,9 +8,9 @@ import { memo, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Virtuoso } from 'react-virtuoso';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
|
||||
import { useClientDataSWR } from '@/libs/swr';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { resourceService } from '@/services/resource';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { INITIAL_STATUS } from '@/store/global/initialState';
|
||||
|
||||
@@ -11,8 +11,8 @@ import {
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import RepoIcon from '@/components/LibIcon';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { useKnowledgeBaseStore } from '@/store/library';
|
||||
|
||||
import ActionIconWithChevron from './ActionIconWithChevron';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { BookMinusIcon, BookPlusIcon, FileBoxIcon, Trash2Icon } from 'lucide-rea
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
|
||||
const styles = createStaticStyles(({ css }) => ({
|
||||
total: css`
|
||||
|
||||
@@ -4,8 +4,8 @@ import { ArrowDownAZ, CalendarIcon, Check, HardDriveIcon } from 'lucide-react';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { type MenuProps } from '@/components/Menu';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
|
||||
import ActionIconWithChevron from './ActionIconWithChevron';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
|
||||
export interface UseFileItemClickOptions {
|
||||
id: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { type FileListItem } from '@/types/files';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { type ViewMode } from '@/app/[variants]/(main)/resource/features/store/initialState';
|
||||
import { parseAsStringEnum, useQueryState } from '@/hooks/useQueryParam';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { type ViewMode } from '@/routes/(main)/resource/features/store/initialState';
|
||||
|
||||
/**
|
||||
* Hook to manage view mode with URL query sync
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { memo, useEffect, useMemo } from 'react';
|
||||
|
||||
import { useFolderPath } from '@/app/[variants]/(main)/resource/features/hooks/useFolderPath';
|
||||
import { useResourceManagerUrlSync } from '@/app/[variants]/(main)/resource/features/hooks/useResourceManagerUrlSync';
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { sortFileList } from '@/app/[variants]/(main)/resource/features/store/selectors';
|
||||
import { useFolderPath } from '@/routes/(main)/resource/features/hooks/useFolderPath';
|
||||
import { useResourceManagerUrlSync } from '@/routes/(main)/resource/features/hooks/useResourceManagerUrlSync';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { sortFileList } from '@/routes/(main)/resource/features/store/selectors';
|
||||
import { useFetchResources, useResourceStore } from '@/store/file/slices/resource/hooks';
|
||||
|
||||
import EmptyPlaceholder from './EmptyPlaceholder';
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { useFolderPath } from '@/app/[variants]/(main)/resource/features/hooks/useFolderPath';
|
||||
import { useAddFilesToKnowledgeBaseModal } from '@/features/LibraryModal';
|
||||
import { useFolderPath } from '@/routes/(main)/resource/features/hooks/useFolderPath';
|
||||
import {
|
||||
useResourceManagerFetchFolderBreadcrumb,
|
||||
useResourceManagerFetchKnowledgeItem,
|
||||
useResourceManagerFetchKnowledgeItems,
|
||||
useResourceManagerStore,
|
||||
} from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { type MultiSelectActionType } from '@/app/[variants]/(main)/resource/features/store/action';
|
||||
import { selectors, sortFileList } from '@/app/[variants]/(main)/resource/features/store/selectors';
|
||||
import { useAddFilesToKnowledgeBaseModal } from '@/features/LibraryModal';
|
||||
} from '@/routes/(main)/resource/features/store';
|
||||
import { type MultiSelectActionType } from '@/routes/(main)/resource/features/store/action';
|
||||
import { selectors, sortFileList } from '@/routes/(main)/resource/features/store/selectors';
|
||||
import { fileManagerSelectors, useFileStore } from '@/store/file';
|
||||
import { type FilesTabs } from '@/types/files';
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@ import { type ChangeEvent } from 'react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { message } from '@/components/AntdStaticMethods';
|
||||
import GuideModal from '@/components/GuideModal';
|
||||
import GuideVideo from '@/components/GuideVideo';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { useFileStore } from '@/store/file';
|
||||
import { FilesTabs } from '@/types/files';
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ import * as motion from 'motion/react-m';
|
||||
import React, { memo, useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import FileIcon from '@/components/FileIcon';
|
||||
import { PAGE_FILE_TYPE } from '@/features/ResourceManager/constants';
|
||||
import {
|
||||
getTransparentDragImage,
|
||||
useDragActive,
|
||||
useDragState,
|
||||
} from '@/app/[variants]/(main)/resource/features/DndContextWrapper';
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import FileIcon from '@/components/FileIcon';
|
||||
import { PAGE_FILE_TYPE } from '@/features/ResourceManager/constants';
|
||||
} from '@/routes/(main)/resource/features/DndContextWrapper';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { useFileStore } from '@/store/file';
|
||||
|
||||
import { useFileItemClick } from '../Explorer/hooks/useFileItemClick';
|
||||
|
||||
@@ -4,8 +4,8 @@ import { Flexbox } from '@lobehub/ui';
|
||||
import { memo, useCallback, useEffect, useMemo, useReducer, useRef } from 'react';
|
||||
import { VList } from 'virtua';
|
||||
|
||||
import { useFolderPath } from '@/app/[variants]/(main)/resource/features/hooks/useFolderPath';
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import { useFolderPath } from '@/routes/(main)/resource/features/hooks/useFolderPath';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { fileService } from '@/services/file';
|
||||
import { useFileStore } from '@/store/file';
|
||||
import { type ResourceQueryParams } from '@/types/resource';
|
||||
|
||||
@@ -6,10 +6,10 @@ import { createStaticStyles, useTheme } from 'antd-style';
|
||||
import { memo, useCallback, useEffect, useMemo } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
||||
import DragUploadZone from '@/components/DragUploadZone';
|
||||
import { PageEditor } from '@/features/PageEditor';
|
||||
import dynamic from '@/libs/next/dynamic';
|
||||
import { useResourceManagerStore } from '@/routes/(main)/resource/features/store';
|
||||
import { documentService } from '@/services/document';
|
||||
import { useFileStore } from '@/store/file';
|
||||
import { documentSelectors } from '@/store/file/slices/document/selectors';
|
||||
|
||||
@@ -6,12 +6,12 @@ import { createStaticStyles, cssVar } from 'antd-style';
|
||||
import { memo, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import Title from '@/app/[variants]/(main)/community/features/Title';
|
||||
import ContentViewer from '@/features/AgentSkillDetail/ContentViewer';
|
||||
import FileTree from '@/features/AgentSkillDetail/FileTree';
|
||||
import { DetailProvider } from '@/features/MCPPluginDetail/DetailProvider';
|
||||
import Tools from '@/features/MCPPluginDetail/Schema/Tools';
|
||||
import { ModeType } from '@/features/MCPPluginDetail/Schema/types';
|
||||
import Title from '@/routes/(main)/community/features/Title';
|
||||
|
||||
import { useDetailContext } from './DetailContext';
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@ import { Flexbox } from '@lobehub/ui';
|
||||
import { type FC } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { navigateToDesktopOnboarding } from '@/app/[variants]/(desktop)/desktop-onboarding/navigation';
|
||||
import { clearDesktopOnboardingCompleted } from '@/app/[variants]/(desktop)/desktop-onboarding/storage';
|
||||
import { DesktopOnboardingScreen } from '@/app/[variants]/(desktop)/desktop-onboarding/types';
|
||||
import BusinessPanelContent from '@/business/client/features/User/BusinessPanelContent';
|
||||
import BrandWatermark from '@/components/BrandWatermark';
|
||||
import Menu from '@/components/Menu';
|
||||
import { isDesktop } from '@/const/version';
|
||||
import { navigateToDesktopOnboarding } from '@/routes/(desktop)/desktop-onboarding/navigation';
|
||||
import { clearDesktopOnboardingCompleted } from '@/routes/(desktop)/desktop-onboarding/storage';
|
||||
import { DesktopOnboardingScreen } from '@/routes/(desktop)/desktop-onboarding/types';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { authSelectors } from '@/store/user/selectors';
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import { OFFICIAL_URL } from '@lobechat/const';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { getDesktopOnboardingCompleted } from '@/app/[variants]/(desktop)/desktop-onboarding/storage';
|
||||
import { isDesktop } from '@/const/version';
|
||||
import { getDesktopOnboardingCompleted } from '@/routes/(desktop)/desktop-onboarding/storage';
|
||||
import { useElectronStore } from '@/store/electron';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { onboardingSelectors } from '@/store/user/selectors';
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
import { memo, useEffect } from 'react';
|
||||
|
||||
import { getDesktopOnboardingCompleted } from '@/app/[variants]/(desktop)/desktop-onboarding/storage';
|
||||
import { getDesktopOnboardingCompleted } from '@/routes/(desktop)/desktop-onboarding/storage';
|
||||
import { useElectronStore } from '@/store/electron';
|
||||
import {
|
||||
getDesktopAutoOidcFirstOpenHandled,
|
||||
@@ -8,7 +8,6 @@ import { lazy, Suspense } from 'react';
|
||||
import { HotkeysProvider } from 'react-hotkeys-hook';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
|
||||
import { DndContextWrapper } from '@/app/[variants]/(main)/resource/features/DndContextWrapper';
|
||||
import Loading from '@/components/Loading/BrandTextLoading';
|
||||
import { isDesktop } from '@/const/version';
|
||||
import { BANNER_HEIGHT } from '@/features/AlertBanner/CloudBanner';
|
||||
@@ -23,6 +22,7 @@ import { usePlatform } from '@/hooks/usePlatform';
|
||||
import { MarketAuthProvider } from '@/layout/AuthProvider/MarketAuth';
|
||||
import CmdkLazy from '@/layout/GlobalProvider/CmdkLazy';
|
||||
import dynamic from '@/libs/next/dynamic';
|
||||
import { DndContextWrapper } from '@/routes/(main)/resource/features/DndContextWrapper';
|
||||
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
||||
import { HotkeyScopeEnum } from '@/types/hotkey';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user