@qilin-agent/client-ui-sidebar-files 0.0.0-stage → 3.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.i18n.yaml +37 -0
- package/README.md +90 -2
- package/README.zh.md +91 -0
- package/lib/client.js +35086 -0
- package/lib/index.js +6 -0
- package/lib/types/client/FileBody.d.ts +11 -0
- package/lib/types/client/FileSearch.d.ts +33 -0
- package/lib/types/client/FileTitle.d.ts +15 -0
- package/lib/types/client/FileTree.d.ts +48 -0
- package/lib/types/client/FilesBody.d.ts +9 -0
- package/lib/types/client/FilesTitle.d.ts +15 -0
- package/lib/types/client/UploadOverlay.d.ts +25 -0
- package/lib/types/client/definition.d.ts +20 -0
- package/lib/types/client/face.d.ts +150 -0
- package/lib/types/client/file-definition.d.ts +27 -0
- package/lib/types/client/file-editor.d.ts +40 -0
- package/lib/types/client/file-face.d.ts +64 -0
- package/lib/types/client/file-failure.d.ts +17 -0
- package/lib/types/client/file-guard.d.ts +34 -0
- package/lib/types/client/file-lang.d.ts +16 -0
- package/lib/types/client/file-mutations.d.ts +148 -0
- package/lib/types/client/file-pages.d.ts +41 -0
- package/lib/types/client/file-preview.d.ts +39 -0
- package/lib/types/client/index.d.ts +79 -0
- package/lib/types/client/locales.d.ts +157 -0
- package/lib/types/client/store.d.ts +189 -0
- package/lib/types/index.d.ts +4 -0
- package/package.json +94 -3
package/lib/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { PropsLocale, PropsRuntime, PropsStore } from '@qilin-agent/client-ui-slots';
|
|
3
|
+
import type { FilesInjected } from './face.ts';
|
|
4
|
+
import type { FileEditorInjected } from './file-face.ts';
|
|
5
|
+
import type { FilePreviewInjected } from './file-preview.ts';
|
|
6
|
+
import type { createFilesStore } from './store.ts';
|
|
7
|
+
/** The body's composed props: the tab it draws, its store, its faces, and its copy. */
|
|
8
|
+
export type FileBodyProps = PropsRuntime<'sidebar.right.pane.tab'> & PropsStore<ReturnType<typeof createFilesStore>> & FilesInjected & FileEditorInjected & FilePreviewInjected & PropsLocale<'sidebarFiles'>;
|
|
9
|
+
/** The file editor's body: the tree pane and the open file's editor pane. */
|
|
10
|
+
export declare function FileBody({ useTabInfo, sessionId, useSessions, useStore, actions, start, toggle, createEntry, renameEntry, removeEntry, readFile, saveFile, openPreview, t, }: FileBodyProps): ReactNode;
|
|
11
|
+
//# sourceMappingURL=FileBody.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The filename search beside the tree: the box in the pane's header strip and
|
|
3
|
+
* the matches it returns, drawn in the tree's place while a query stands.
|
|
4
|
+
*
|
|
5
|
+
* Both halves are pure props: the box reports keystrokes and the results report
|
|
6
|
+
* a click, and the body owns what either means. Paths here are the Host's
|
|
7
|
+
* workspace-relative matches, split for display only.
|
|
8
|
+
*/
|
|
9
|
+
import type { ReactNode } from 'react';
|
|
10
|
+
import type { TranslateNS } from '@qilin-agent/client-locale/client';
|
|
11
|
+
import type { FileSearchState } from './store.ts';
|
|
12
|
+
/**
|
|
13
|
+
* The search box.
|
|
14
|
+
* @param props - the box's text, the two gestures, and its copy.
|
|
15
|
+
* @returns the input row.
|
|
16
|
+
*/
|
|
17
|
+
export declare function FileSearchBox(props: {
|
|
18
|
+
readonly query: string;
|
|
19
|
+
readonly onQuery: (query: string) => void;
|
|
20
|
+
readonly onClear: () => void;
|
|
21
|
+
readonly t: TranslateNS<'sidebarFiles'>;
|
|
22
|
+
}): ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* The matches, or one line naming why there are none.
|
|
25
|
+
* @param props - the search's state, the open gesture, and its copy.
|
|
26
|
+
* @returns the rows of the results list.
|
|
27
|
+
*/
|
|
28
|
+
export declare function FileSearchResults(props: {
|
|
29
|
+
readonly state: FileSearchState;
|
|
30
|
+
readonly onOpen: (path: string) => void;
|
|
31
|
+
readonly t: TranslateNS<'sidebarFiles'>;
|
|
32
|
+
}): ReactNode;
|
|
33
|
+
//# sourceMappingURL=FileSearch.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `file` type's chip title: the open file's type sheet before its basename.
|
|
3
|
+
* Registered under `sidebar.right.pane.tab.title`. The glyph classifies the
|
|
4
|
+
* captured title — the address's decoded basename — so each file carries its
|
|
5
|
+
* own sheet, which is why the type declares no static `icon`.
|
|
6
|
+
*/
|
|
7
|
+
import type { ReactNode } from 'react';
|
|
8
|
+
import type { PropsRuntime } from '@qilin-agent/client-ui-slots';
|
|
9
|
+
/**
|
|
10
|
+
* The title as the chip and a floating panel's header show it.
|
|
11
|
+
* @param props - the tab information hook.
|
|
12
|
+
* @returns the file's type sheet followed by its basename.
|
|
13
|
+
*/
|
|
14
|
+
export declare function FileTitle({ useTabInfo }: PropsRuntime<'sidebar.right.pane.tab.title'>): ReactNode;
|
|
15
|
+
//# sourceMappingURL=FileTitle.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { RemoteFailure } from '@qilin-agent/api-remotes/client';
|
|
3
|
+
import type { TranslateNS } from '@qilin-agent/client-locale/client';
|
|
4
|
+
import type { WorkspaceDirectoryEntry } from '@qilin-agent/api-workspace-files/types';
|
|
5
|
+
import type { EntryKind } from './file-mutations.ts';
|
|
6
|
+
import type { FilesTabState } from './store.ts';
|
|
7
|
+
/**
|
|
8
|
+
* Order one level's entries for display: directories first, then everything
|
|
9
|
+
* else, each group by name. The endpoint's order is a listing fact; this is the
|
|
10
|
+
* reader's.
|
|
11
|
+
* @param entries - the listing as the endpoint returned it.
|
|
12
|
+
* @returns a new array, directories first, then by name within each group.
|
|
13
|
+
*/
|
|
14
|
+
export declare function orderEntries(entries: readonly WorkspaceDirectoryEntry[]): WorkspaceDirectoryEntry[];
|
|
15
|
+
/**
|
|
16
|
+
* Say why a directory could not be listed, in terms of the directory.
|
|
17
|
+
* @param t - namespace-bound translate.
|
|
18
|
+
* @param failure - the settled Remote failure.
|
|
19
|
+
* @returns the line to show under the directory.
|
|
20
|
+
*/
|
|
21
|
+
export declare function failureLine(t: TranslateNS<'sidebarFiles'>, failure: RemoteFailure): string;
|
|
22
|
+
/**
|
|
23
|
+
* The text one row's menu copies.
|
|
24
|
+
* @param root - the workspace root, the prefix relative paths drop.
|
|
25
|
+
* @param path - the row's absolute path.
|
|
26
|
+
* @param form - whether the copy keeps or drops the root prefix.
|
|
27
|
+
* @returns `.` for the root itself, the suffix after the root's `/` when under
|
|
28
|
+
* it, and the absolute path for a tree rooted somewhere neither covers.
|
|
29
|
+
*/
|
|
30
|
+
export declare function copyTextOf(root: string, path: string, form: 'relative' | 'absolute'): string;
|
|
31
|
+
/**
|
|
32
|
+
* The tree itself: the root level, whatever the reader has opened under it, and
|
|
33
|
+
* the one context menu its rows and its background share.
|
|
34
|
+
* @param props - the tab's tree state, its gestures, its copy, and the row
|
|
35
|
+
* mutations it dispatches.
|
|
36
|
+
* @returns the root level's rows, with the menu and both dialogs in portals.
|
|
37
|
+
*/
|
|
38
|
+
export declare function FileTree(props: {
|
|
39
|
+
readonly state: FilesTabState;
|
|
40
|
+
readonly onToggle: (path: string) => void;
|
|
41
|
+
readonly onOpen: (path: string) => void;
|
|
42
|
+
readonly onCreate: (directory: string, name: string, kind: EntryKind) => void;
|
|
43
|
+
readonly onRename: (path: string, name: string) => void;
|
|
44
|
+
readonly onDelete: (path: string, kind: EntryKind) => void;
|
|
45
|
+
readonly onDismissMutation: () => void;
|
|
46
|
+
readonly t: TranslateNS<'sidebarFiles'>;
|
|
47
|
+
}): ReactNode;
|
|
48
|
+
//# sourceMappingURL=FileTree.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { FilesInjected } from './face.ts';
|
|
3
|
+
import type { PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore } from '@qilin-agent/client-ui-slots';
|
|
4
|
+
import type { createFilesStore } from './store.ts';
|
|
5
|
+
/** The body's composed props: the tab it draws, its store, its face, and its copy. */
|
|
6
|
+
export type FilesBodyProps = PropsRuntime<'sidebar.right.pane.tab'> & PropsStore<ReturnType<typeof createFilesStore>> & FilesInjected & PropsLocale<'sidebarFiles'> & PropsRenderSlots<'sidebar.right.tab.files.actions'>;
|
|
7
|
+
/** The file tree's body: the workspace root and whatever the reader has opened under it. */
|
|
8
|
+
export declare function FilesBody({ useTabInfo, sessionId, useSessions, useStore, actions, start, load, toggle, search, createEntry, renameEntry, removeEntry, t, renderSlot, }: FilesBodyProps): ReactNode;
|
|
9
|
+
//# sourceMappingURL=FilesBody.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The files type's chip title: the folder sheet before the type's label.
|
|
3
|
+
* Registered under `sidebar.right.pane.tab.title`; without it the chip would
|
|
4
|
+
* show the bare label. The tree in the body draws its own row glyphs and never
|
|
5
|
+
* this one.
|
|
6
|
+
*/
|
|
7
|
+
import type { ReactNode } from 'react';
|
|
8
|
+
import type { PropsRuntime } from '@qilin-agent/client-ui-slots';
|
|
9
|
+
/**
|
|
10
|
+
* The title as the chip and a floating panel's header show it.
|
|
11
|
+
* @param props - the tab information hook.
|
|
12
|
+
* @returns the folder sheet followed by the tab's title text.
|
|
13
|
+
*/
|
|
14
|
+
export declare function FilesTitle({ useTabInfo }: PropsRuntime<'sidebar.right.pane.tab.title'>): ReactNode;
|
|
15
|
+
//# sourceMappingURL=FilesTitle.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upload overlay for the files page: a drag-and-drop target over the file
|
|
3
|
+
* tree that PUTs each dropped file to the preview-media upload route,
|
|
4
|
+
* relative to the tree's displayed root. The tree reloads on success.
|
|
5
|
+
*/
|
|
6
|
+
import { type ReactNode } from 'react';
|
|
7
|
+
/** Props: the session and root the upload resolves against, plus reload. */
|
|
8
|
+
export interface UploadOverlayProps {
|
|
9
|
+
readonly sessionId: string;
|
|
10
|
+
/** The tree's displayed workspace root; dropped relative paths resolve under it. */
|
|
11
|
+
readonly root: string;
|
|
12
|
+
/** Ask the owner to refresh the tree after uploads land. */
|
|
13
|
+
readonly onUploaded: () => void;
|
|
14
|
+
/** Localized copy for the overlay and its report. */
|
|
15
|
+
readonly t: import('@qilin-agent/client-ui-slots').TranslateNS<'sidebarFiles'>;
|
|
16
|
+
/** The wrapped tree. */
|
|
17
|
+
readonly children: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Wrap one file tree with a drag-and-drop upload overlay.
|
|
21
|
+
* @param props - session identity, displayed root, reload callback, copy.
|
|
22
|
+
* @returns the overlay that mounts over the tree while a drag is active.
|
|
23
|
+
*/
|
|
24
|
+
export declare function UploadOverlay({ sessionId, root, onUploaded, t, children }: UploadOverlayProps): ReactNode;
|
|
25
|
+
//# sourceMappingURL=UploadOverlay.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage one of this package's registration: what the `files` tab type IS.
|
|
3
|
+
*
|
|
4
|
+
* The type is a page, not a viewer: it claims no address. The guide page offers
|
|
5
|
+
* it as an entry box, and the tree opens files through `tabActions.openResource`
|
|
6
|
+
* for the `qilin-resource://file` viewers to claim.
|
|
7
|
+
*/
|
|
8
|
+
import type { SidebarRightTabDefinition } from '@qilin-agent/client-ui-sidebar-right/client';
|
|
9
|
+
import type { TranslateNS } from '@qilin-agent/client-locale/client';
|
|
10
|
+
/** The tab kind this package owns. */
|
|
11
|
+
export declare const FILES_KIND = "files";
|
|
12
|
+
/** This implementation's identity in the tab system, and the key its body registers under. */
|
|
13
|
+
export declare const FILES_ID = "@qilin-agent/client-ui-sidebar-files";
|
|
14
|
+
/**
|
|
15
|
+
* The files type's registry definition.
|
|
16
|
+
* @param t - namespace-bound translate, read fresh on every label call.
|
|
17
|
+
* @returns the definition to register.
|
|
18
|
+
*/
|
|
19
|
+
export declare function filesDefinition(t: TranslateNS<'sidebarFiles'>): SidebarRightTabDefinition;
|
|
20
|
+
//# sourceMappingURL=definition.d.ts.map
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tree's asynchronous half: listing directories into the store, and the
|
|
3
|
+
* row mutations that change what a directory holds.
|
|
4
|
+
*
|
|
5
|
+
* The component never awaits anything. It calls `start` / `load` / `toggle` /
|
|
6
|
+
* `search` / `createEntry` / `renameEntry` / `removeEntry`, and this face
|
|
7
|
+
* performs the work and writes the outcome through the store's own actions —
|
|
8
|
+
* the Slot-standard `inject` shape, so the session id is resolved by the
|
|
9
|
+
* framework and the write set stays the store's.
|
|
10
|
+
*
|
|
11
|
+
* The listing itself is bound here to the Client Remote face: the tree keys
|
|
12
|
+
* every level by absolute path and hands the endpoint that same absolute path;
|
|
13
|
+
* the endpoint answers with the directory's workspace-relative path as well,
|
|
14
|
+
* which the tree has no use for and drops. The mutations are bound the same
|
|
15
|
+
* way, and their successful settlement re-lists the directory that held the
|
|
16
|
+
* entry and reconciles the tabs open on the touched path.
|
|
17
|
+
*
|
|
18
|
+
* One level has one listing in force, and one tab has one mutation in force:
|
|
19
|
+
* asking for a level again — the reload gesture, a directory reopened after a
|
|
20
|
+
* reset — retires the listing still in flight for it, and a newer gesture
|
|
21
|
+
* retires the mutation still out, whose settlement then writes nothing.
|
|
22
|
+
* Cleanup rides the owner's `signal`: a request is not made for a record that
|
|
23
|
+
* already ended, and when the record goes away the bucket and the tab's
|
|
24
|
+
* listing bookkeeping are forgotten, so no later settlement writes to it.
|
|
25
|
+
*/
|
|
26
|
+
import type { ClientRemote, RemoteResult } from '@qilin-agent/api-remotes/client';
|
|
27
|
+
import type { BoundActions } from '@qilin-agent/client-store';
|
|
28
|
+
import type { TabId } from '@qilin-agent/client-ui-dockkit';
|
|
29
|
+
import type { WorkspaceFileNameSearch } from '@qilin-agent/api-workspace-files/types';
|
|
30
|
+
import type { SessionId } from '@qilin-agent/session/types';
|
|
31
|
+
import type { EntryKind, TabReconcile, WorkspaceFileMutations } from './file-mutations.ts';
|
|
32
|
+
import type { DirLevel, createFilesStore } from './store.ts';
|
|
33
|
+
/**
|
|
34
|
+
* One directory listing, bound to a Remote face.
|
|
35
|
+
*
|
|
36
|
+
* The session travels with the call because the endpoint resolves the workspace
|
|
37
|
+
* root from it: the same path means different directories in different sessions.
|
|
38
|
+
* A Remote call does not reject — the result carries the failure.
|
|
39
|
+
*/
|
|
40
|
+
export type ListWorkspaceDirectory = (sessionId: SessionId, path: string, signal: AbortSignal) => Promise<RemoteResult<DirLevel>>;
|
|
41
|
+
/**
|
|
42
|
+
* One filename search, bound to a Remote face.
|
|
43
|
+
*
|
|
44
|
+
* The query is matched against basenames below the same workspace root the
|
|
45
|
+
* listing is rooted at, and the answer is workspace-relative paths.
|
|
46
|
+
*/
|
|
47
|
+
export type SearchWorkspaceFileNames = (sessionId: SessionId, query: string, signal: AbortSignal) => Promise<RemoteResult<WorkspaceFileNameSearch>>;
|
|
48
|
+
/**
|
|
49
|
+
* The slice of the Client Remote face this package calls: the `workspaceFiles`
|
|
50
|
+
* namespace's `list` and `searchNames`, exactly as the Host's generated client
|
|
51
|
+
* declares them.
|
|
52
|
+
*/
|
|
53
|
+
export type WorkspaceFilesTreeRemote = {
|
|
54
|
+
readonly workspaceFiles: Pick<ClientRemote['workspaceFiles'], 'list' | 'searchNames'>;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Bind the listing to one Remote face, keeping only what the tree stores.
|
|
58
|
+
* @param remote - the Client Remote face carrying the `workspaceFiles` namespace's `list`.
|
|
59
|
+
* @returns the listing the tree's face performs.
|
|
60
|
+
*/
|
|
61
|
+
export declare function createList(remote: {
|
|
62
|
+
readonly workspaceFiles: Pick<ClientRemote['workspaceFiles'], 'list'>;
|
|
63
|
+
}): ListWorkspaceDirectory;
|
|
64
|
+
/**
|
|
65
|
+
* How long the box settles before a query reaches the Host. Keystrokes that
|
|
66
|
+
* arrive inside the window replace the pending query instead of asking the
|
|
67
|
+
* Host for a prefix nobody wants finished.
|
|
68
|
+
*/
|
|
69
|
+
export declare const SEARCH_SETTLE_MS = 200;
|
|
70
|
+
/**
|
|
71
|
+
* Bind the filename search to one Remote face, dropping the entries this
|
|
72
|
+
* package does not draw.
|
|
73
|
+
* @param remote - the Client Remote face carrying the `workspaceFiles` namespace's `searchNames`.
|
|
74
|
+
* @returns the search the tree's face performs.
|
|
75
|
+
*/
|
|
76
|
+
export declare function createSearch(remote: {
|
|
77
|
+
readonly workspaceFiles: Pick<ClientRemote['workspaceFiles'], 'searchNames'>;
|
|
78
|
+
}): SearchWorkspaceFileNames;
|
|
79
|
+
/**
|
|
80
|
+
* The tree's injected business face, as the body receives it.
|
|
81
|
+
*/
|
|
82
|
+
export interface FilesInjected {
|
|
83
|
+
/**
|
|
84
|
+
* Seed this tab's tree and list its root.
|
|
85
|
+
* @param tabId - the tab being drawn.
|
|
86
|
+
* @param root - absolute path of the workspace root.
|
|
87
|
+
* @param signal - the tab record's lifetime.
|
|
88
|
+
*/
|
|
89
|
+
readonly start: (tabId: TabId, root: string, signal: AbortSignal) => void;
|
|
90
|
+
/**
|
|
91
|
+
* List one directory into the store.
|
|
92
|
+
* @param tabId - the tab being drawn.
|
|
93
|
+
* @param path - absolute directory path.
|
|
94
|
+
* @param signal - the tab record's lifetime.
|
|
95
|
+
*/
|
|
96
|
+
readonly load: (tabId: TabId, path: string, signal: AbortSignal) => void;
|
|
97
|
+
/**
|
|
98
|
+
* Open or collapse one directory, listing it the first time it opens.
|
|
99
|
+
* @param tabId - the tab being drawn.
|
|
100
|
+
* @param path - absolute directory path.
|
|
101
|
+
* @param loaded - whether this level already has state.
|
|
102
|
+
* @param signal - the tab record's lifetime.
|
|
103
|
+
*/
|
|
104
|
+
readonly toggle: (tabId: TabId, path: string, loaded: boolean, signal: AbortSignal) => void;
|
|
105
|
+
/**
|
|
106
|
+
* Ask for the files whose names contain one query, after the box settles.
|
|
107
|
+
* @param tabId - the tab being drawn.
|
|
108
|
+
* @param query - the box's text, exactly as typed; blank asks nothing.
|
|
109
|
+
* @param signal - the tab record's lifetime.
|
|
110
|
+
*/
|
|
111
|
+
readonly search: (tabId: TabId, query: string, signal: AbortSignal) => void;
|
|
112
|
+
/**
|
|
113
|
+
* Create one empty file or one directory inside a listed directory.
|
|
114
|
+
* @param tabId - the tab being drawn.
|
|
115
|
+
* @param directory - absolute path of the directory to create the entry in.
|
|
116
|
+
* @param name - the entry name, already normalized by the caller.
|
|
117
|
+
* @param kind - whether to write an empty file or make a directory.
|
|
118
|
+
* @param signal - the tab record's lifetime.
|
|
119
|
+
*/
|
|
120
|
+
readonly createEntry: (tabId: TabId, directory: string, name: string, kind: EntryKind, signal: AbortSignal) => void;
|
|
121
|
+
/**
|
|
122
|
+
* Rename one entry in place, keeping it in its own directory.
|
|
123
|
+
* @param tabId - the tab being drawn.
|
|
124
|
+
* @param path - absolute path of the entry to rename.
|
|
125
|
+
* @param name - the entry name, already normalized by the caller.
|
|
126
|
+
* @param root - absolute workspace root, which the tabs' addresses are relative to.
|
|
127
|
+
* @param signal - the tab record's lifetime.
|
|
128
|
+
*/
|
|
129
|
+
readonly renameEntry: (tabId: TabId, path: string, name: string, root: string, signal: AbortSignal) => void;
|
|
130
|
+
/**
|
|
131
|
+
* Delete one entry; a directory goes with everything inside it.
|
|
132
|
+
* @param tabId - the tab being drawn.
|
|
133
|
+
* @param path - absolute path of the entry to delete.
|
|
134
|
+
* @param kind - whether the entry is a directory, which decides `recursive`.
|
|
135
|
+
* @param root - absolute workspace root, which the tabs' addresses are relative to.
|
|
136
|
+
* @param signal - the tab record's lifetime.
|
|
137
|
+
*/
|
|
138
|
+
readonly removeEntry: (tabId: TabId, path: string, kind: EntryKind, root: string, signal: AbortSignal) => void;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Bind the tree's face to one directory listing, one filename search, and the
|
|
142
|
+
* row mutations.
|
|
143
|
+
* @param list - the bound `workspaceFiles.list` call.
|
|
144
|
+
* @param searchNames - the bound `workspaceFiles.searchNames` call.
|
|
145
|
+
* @param mutations - the bound create, move, and remove calls.
|
|
146
|
+
* @param reconcile - how a touched path is settled against the open tabs.
|
|
147
|
+
* @returns the Slot `inject` factory: session and bound actions in, face out.
|
|
148
|
+
*/
|
|
149
|
+
export declare function filesFace(list: ListWorkspaceDirectory, searchNames: SearchWorkspaceFileNames, mutations: WorkspaceFileMutations, reconcile: TabReconcile): (sessionId: SessionId, actions: BoundActions<ReturnType<typeof createFilesStore>>) => FilesInjected;
|
|
150
|
+
//# sourceMappingURL=face.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage one of the `file` tab type's registration: the workspace file editor.
|
|
3
|
+
*
|
|
4
|
+
* A resource type in the `builtin` band claiming every session-scoped file
|
|
5
|
+
* address `file-guard` accepts — text and code extensions only, so images,
|
|
6
|
+
* PDFs, and unknown extensions fall through to the `text` fallback viewer.
|
|
7
|
+
* Markdown is a text extension, so this editor claims it and the preview
|
|
8
|
+
* control opens the rendered document. One tab opens per address: the registry's default, and the reason
|
|
9
|
+
* the type declares no `single` and no guide entry.
|
|
10
|
+
*/
|
|
11
|
+
import type { SidebarRightTabDefinition } from '@qilin-agent/client-ui-sidebar-right/client';
|
|
12
|
+
import type { TranslateNS } from '@qilin-agent/client-locale/client';
|
|
13
|
+
/** The editor tab kind this package owns beside the `files` page. */
|
|
14
|
+
export declare const FILE_KIND = "file";
|
|
15
|
+
/** This implementation's identity, and the key its body and title register under. */
|
|
16
|
+
export declare const FILE_ID = "@qilin-agent/client-ui-sidebar-files/file";
|
|
17
|
+
/**
|
|
18
|
+
* The editor type's registry definition.
|
|
19
|
+
*
|
|
20
|
+
* No static `icon`: the chip's glyph comes from the title slot, which draws
|
|
21
|
+
* the file-type sheet for the open file's own name — a static type glyph here
|
|
22
|
+
* could not classify by path and would double the chip's sheet.
|
|
23
|
+
* @param t - namespace-bound translate, read fresh on every label call.
|
|
24
|
+
* @returns the definition to register.
|
|
25
|
+
*/
|
|
26
|
+
export declare function fileDefinition(t: TranslateNS<'sidebarFiles'>): SidebarRightTabDefinition;
|
|
27
|
+
//# sourceMappingURL=file-definition.d.ts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { EditorView } from '@codemirror/view';
|
|
2
|
+
/** What the body holds after mounting, and what it can change in place. */
|
|
3
|
+
export interface FileEditorHandle {
|
|
4
|
+
/** The live view: the body needs nothing from it; specs and callers do. */
|
|
5
|
+
readonly view: EditorView;
|
|
6
|
+
/** Destroy the view and detach its DOM. */
|
|
7
|
+
destroy(): void;
|
|
8
|
+
/** @returns the editor's current document. */
|
|
9
|
+
getDocument(): string;
|
|
10
|
+
/**
|
|
11
|
+
* Turn line wrapping on or off without disturbing the document, history,
|
|
12
|
+
* or scroll position.
|
|
13
|
+
* @param wrap - whether lines wrap.
|
|
14
|
+
*/
|
|
15
|
+
setWrap(wrap: boolean): void;
|
|
16
|
+
}
|
|
17
|
+
/** What one mount needs: the document, its grammar, and the two gestures. */
|
|
18
|
+
export interface FileEditorOptions {
|
|
19
|
+
/** The initial document: the loaded text, or the unsaved draft. */
|
|
20
|
+
readonly text: string;
|
|
21
|
+
/** The file's path, for the grammar. */
|
|
22
|
+
readonly path: string;
|
|
23
|
+
/** Whether lines wrap initially. */
|
|
24
|
+
readonly wrap: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Called after every document change with the whole document.
|
|
27
|
+
* @param text - the editor document.
|
|
28
|
+
*/
|
|
29
|
+
readonly onDocumentChange: (text: string) => void;
|
|
30
|
+
/** Called for the platform save gesture (`Mod-s`). */
|
|
31
|
+
readonly onSave: () => void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Mount one editor view into `host`.
|
|
35
|
+
* @param host - the element the view attaches to; its size is the editor's.
|
|
36
|
+
* @param options - the document, its grammar, and the two gestures.
|
|
37
|
+
* @returns the handle the body keeps until unmount.
|
|
38
|
+
*/
|
|
39
|
+
export declare function mountFileEditor(host: HTMLElement, options: FileEditorOptions): FileEditorHandle;
|
|
40
|
+
//# sourceMappingURL=file-editor.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor's asynchronous half: reading the whole file, saving it back.
|
|
3
|
+
*
|
|
4
|
+
* The component never awaits anything. It calls `readFile` / `saveFile`, and
|
|
5
|
+
* this face performs the calls and writes the outcome through the store's own
|
|
6
|
+
* actions — the Slot-standard `inject` shape, so the write set stays the
|
|
7
|
+
* store's. The session travels inside `file`: it comes from the tab's
|
|
8
|
+
* address, whose session authorizes the read and the write, not from the
|
|
9
|
+
* slot's.
|
|
10
|
+
*
|
|
11
|
+
* One tab has one call in force: a reload while a read is still out, or a
|
|
12
|
+
* save overtaken by another, retires the older call, whose settlement then
|
|
13
|
+
* writes nothing. Cleanup rides the owner's `signal`, armed by the tab's
|
|
14
|
+
* first call: the abort forgets the bucket and this bookkeeping, a request is
|
|
15
|
+
* not made for a record that already ended, and a settlement arriving after
|
|
16
|
+
* the record is gone has nothing left to write to.
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import type { BoundActions } from '@qilin-agent/client-store';
|
|
20
|
+
import type { RemoteResult } from '@qilin-agent/api-remotes/client';
|
|
21
|
+
import type { WorkspaceFileStat } from '@qilin-agent/api-workspace-files/types';
|
|
22
|
+
import type { TabId } from '@qilin-agent/client-ui-dockkit';
|
|
23
|
+
import type { SessionId } from '@qilin-agent/session/types';
|
|
24
|
+
import type { WholeFileResult } from './file-pages.ts';
|
|
25
|
+
import type { SessionFile } from './file-guard.ts';
|
|
26
|
+
import type { createFilesStore } from './store.ts';
|
|
27
|
+
/** The bound `workspaceFiles.write` call, as the generated client declares it. */
|
|
28
|
+
export type WriteWorkspaceFile = (sessionId: SessionId, path: string, text: string, request: {
|
|
29
|
+
readonly baseVersion?: string;
|
|
30
|
+
}, signal: AbortSignal) => Promise<RemoteResult<WorkspaceFileStat>>;
|
|
31
|
+
/** What one save writes against. */
|
|
32
|
+
export interface SaveOptions {
|
|
33
|
+
/** The version the text was read at; refused with `workspace-file/stale` when the disk moved on. */
|
|
34
|
+
readonly baseVersion: string;
|
|
35
|
+
/** `true` omits `baseVersion`: the conflict's overwrite. */
|
|
36
|
+
readonly force: boolean;
|
|
37
|
+
}
|
|
38
|
+
/** The editor's injected face, as the body receives it. */
|
|
39
|
+
export interface FileEditorInjected {
|
|
40
|
+
/**
|
|
41
|
+
* Read the whole file into the store, resetting the editor's bucket.
|
|
42
|
+
* @param tabId - the tab being drawn.
|
|
43
|
+
* @param file - the session and path the tab's address names.
|
|
44
|
+
* @param signal - the tab record's lifetime.
|
|
45
|
+
*/
|
|
46
|
+
readonly readFile: (tabId: TabId, file: SessionFile, signal: AbortSignal) => void;
|
|
47
|
+
/**
|
|
48
|
+
* Save one text as the file's content.
|
|
49
|
+
* @param tabId - the tab being drawn.
|
|
50
|
+
* @param file - the session and path the tab's address names.
|
|
51
|
+
* @param text - the complete text to write.
|
|
52
|
+
* @param options - the version written against, or a forced overwrite.
|
|
53
|
+
* @param signal - the tab record's lifetime.
|
|
54
|
+
*/
|
|
55
|
+
readonly saveFile: (tabId: TabId, file: SessionFile, text: string, options: SaveOptions, signal: AbortSignal) => void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Bind the editor's face to one whole-file read and one write.
|
|
59
|
+
* @param readWhole - the paged whole-file read.
|
|
60
|
+
* @param write - the bound `workspaceFiles.write` call.
|
|
61
|
+
* @returns the Slot `inject` factory: session and bound actions in, face out.
|
|
62
|
+
*/
|
|
63
|
+
export declare function fileEditFace(readWhole: (sessionId: SessionId, path: string, signal: AbortSignal) => Promise<WholeFileResult>, write: WriteWorkspaceFile): (sessionId: SessionId, actions: BoundActions<ReturnType<typeof createFilesStore>>) => FileEditorInjected;
|
|
64
|
+
//# sourceMappingURL=file-face.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The failure line one Remote code deserves, in terms of the file the editor
|
|
3
|
+
* could not read or save. Kept apart from the component so the mapping is
|
|
4
|
+
* testable on its own; codes this editor does not name fall to the generic
|
|
5
|
+
* line carrying the carrier's message.
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import type { RemoteFailure } from '@qilin-agent/api-remotes/client';
|
|
9
|
+
import type { TranslateNS } from '@qilin-agent/client-locale/client';
|
|
10
|
+
/**
|
|
11
|
+
* Say what went wrong, in terms of the file rather than of the transport.
|
|
12
|
+
* @param t - namespace-bound translate.
|
|
13
|
+
* @param failure - the settled Remote failure.
|
|
14
|
+
* @returns the line to show in the editor pane.
|
|
15
|
+
*/
|
|
16
|
+
export declare function fileFailureLine(t: TranslateNS<'sidebarFiles'>, failure: RemoteFailure): string;
|
|
17
|
+
//# sourceMappingURL=file-failure.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { SessionId } from '@qilin-agent/session/types';
|
|
2
|
+
/** The session and path one claimed address names, as the endpoints receive them. */
|
|
3
|
+
export interface SessionFile {
|
|
4
|
+
/** The Session whose workspace resolves relative paths and authorizes writes. */
|
|
5
|
+
readonly sessionId: SessionId;
|
|
6
|
+
/** The path handed to the Host, absolute or workspace-relative. */
|
|
7
|
+
readonly path: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The type's `canOpen`: take only session-scoped addresses whose path is
|
|
11
|
+
* editable. An absolute address is refused because saving it has no
|
|
12
|
+
* authorizing Session, so the read-only `text` viewer keeps it.
|
|
13
|
+
* @param address - a candidate resource address.
|
|
14
|
+
* @returns whether the type opens the address.
|
|
15
|
+
*/
|
|
16
|
+
export declare function canOpenFileAddress(address: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* The tab title for one file address: the decoded basename, as the chip names
|
|
19
|
+
* the open file. A malformed percent sequence shows raw rather than refusing
|
|
20
|
+
* the address.
|
|
21
|
+
* @param address - a file-shaped resource address.
|
|
22
|
+
* @returns the decoded last path segment.
|
|
23
|
+
*/
|
|
24
|
+
export declare function fileTabTitle(address: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* The session and path one claimed address names.
|
|
27
|
+
*
|
|
28
|
+
* The registry routes only addresses `canOpenFileAddress` accepted, so a
|
|
29
|
+
* non-session address here is a programming error and throws.
|
|
30
|
+
* @param address - a tab's qilin-resource://file/ address.
|
|
31
|
+
* @returns the session and the path to hand the endpoints.
|
|
32
|
+
*/
|
|
33
|
+
export declare function sessionFileOf(address: string): SessionFile;
|
|
34
|
+
//# sourceMappingURL=file-guard.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language grammar for one file path, as the editor mounts it.
|
|
3
|
+
*
|
|
4
|
+
* The map covers the installed `@codemirror/lang-*` packages plus the legacy
|
|
5
|
+
* modes worth carrying for shell-family and config files; an unmapped path
|
|
6
|
+
* edits as plain text.
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import type { Extension } from '@codemirror/state';
|
|
10
|
+
/**
|
|
11
|
+
* The grammar for one file path, from its extension.
|
|
12
|
+
* @param path - the path the Host receives.
|
|
13
|
+
* @returns the language extension, or `undefined` for a path edited as plain text.
|
|
14
|
+
*/
|
|
15
|
+
export declare function langForPath(path: string): Extension | undefined;
|
|
16
|
+
//# sourceMappingURL=file-lang.d.ts.map
|