team-connect 0.1.0
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/README.md +315 -0
- package/dist/components/AuthBar.d.ts +6 -0
- package/dist/components/AuthBar.d.ts.map +1 -0
- package/dist/components/AuthBar.js +16 -0
- package/dist/components/AuthBar.js.map +1 -0
- package/dist/components/Breadcrumbs.d.ts +8 -0
- package/dist/components/Breadcrumbs.d.ts.map +1 -0
- package/dist/components/Breadcrumbs.js +6 -0
- package/dist/components/Breadcrumbs.js.map +1 -0
- package/dist/components/FileBrowser.d.ts +7 -0
- package/dist/components/FileBrowser.d.ts.map +1 -0
- package/dist/components/FileBrowser.js +47 -0
- package/dist/components/FileBrowser.js.map +1 -0
- package/dist/components/FileList.d.ts +11 -0
- package/dist/components/FileList.d.ts.map +1 -0
- package/dist/components/FileList.js +25 -0
- package/dist/components/FileList.js.map +1 -0
- package/dist/components/SearchBar.d.ts +7 -0
- package/dist/components/SearchBar.d.ts.map +1 -0
- package/dist/components/SearchBar.js +29 -0
- package/dist/components/SearchBar.js.map +1 -0
- package/dist/components/UploadZone.d.ts +7 -0
- package/dist/components/UploadZone.d.ts.map +1 -0
- package/dist/components/UploadZone.js +19 -0
- package/dist/components/UploadZone.js.map +1 -0
- package/dist/hooks/useFiles.d.ts +16 -0
- package/dist/hooks/useFiles.d.ts.map +1 -0
- package/dist/hooks/useFiles.js +99 -0
- package/dist/hooks/useFiles.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/sp-client.d.ts +9 -0
- package/dist/lib/sp-client.d.ts.map +1 -0
- package/dist/lib/sp-client.js +140 -0
- package/dist/lib/sp-client.js.map +1 -0
- package/dist/lib/utils.d.ts +9 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +71 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +58 -0
- package/proxy/config/private.json +3 -0
- package/proxy/go.mod +34 -0
- package/proxy/go.sum +116 -0
- package/proxy/main.go +134 -0
- package/proxy/team-connect-proxy +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# team-connect
|
|
2
|
+
|
|
3
|
+
SharePoint file browser for React / Next.js — browse, upload, download and manage files through a local Go proxy.
|
|
4
|
+
**No Azure AD app registration required.** Auth is handled by [gosip](https://github.com/koltyakov/gosip)'s interactive browser login (FedAuth cookies).
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## How it works
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
┌──────────────┐ ┌──────────────┐ ┌───────────────────┐
|
|
12
|
+
│ React app │──────▶│ Go proxy │──────▶│ SharePoint REST │
|
|
13
|
+
│ (port 3000) │ HTTP │ (port 8080) │ Auth │ API (/_api/web) │
|
|
14
|
+
└──────────────┘ └──────────────┘ └───────────────────┘
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
1. The **Go proxy** starts, opens Chrome, you log in with SSO — gosip captures the FedAuth cookie.
|
|
18
|
+
2. All SharePoint REST calls from your React app go through `http://localhost:8080/sp/…`.
|
|
19
|
+
3. The proxy injects auth headers and forwards requests to SharePoint.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
### 1. Install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install team-connect
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 2. Set up the Go proxy
|
|
32
|
+
|
|
33
|
+
**Prerequisites:** Go 1.19+
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Clone gosip-sandbox (provides the ondemand auth strategy)
|
|
37
|
+
git clone https://github.com/koltyakov/gosip-sandbox.git
|
|
38
|
+
|
|
39
|
+
# Copy the proxy from the package (or from the repo)
|
|
40
|
+
cp -r node_modules/team-connect/proxy ./team-connect-proxy
|
|
41
|
+
cd team-connect-proxy
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Edit `config/private.json` with your SharePoint site URL:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"siteUrl": "https://yourtenant.sharepoint.com/sites/YourSite"
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Update the `replace` directive in `go.mod` to point to your local gosip-sandbox path:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
replace github.com/koltyakov/gosip-sandbox => /path/to/gosip-sandbox
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Build and run:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
go build -o proxy .
|
|
62
|
+
./proxy
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Chrome will open — log in with your org account. The proxy will confirm:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Connected to: Your Site (https://yourtenant.sharepoint.com/sites/YourSite)
|
|
69
|
+
Proxy listening on http://localhost:8080
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 3. Add environment variables
|
|
73
|
+
|
|
74
|
+
In your Next.js `.env.local`:
|
|
75
|
+
|
|
76
|
+
```env
|
|
77
|
+
NEXT_PUBLIC_PROXY_URL=http://localhost:8080
|
|
78
|
+
NEXT_PUBLIC_SHAREPOINT_DOCUMENT_LIBRARY=Shared Documents
|
|
79
|
+
NEXT_PUBLIC_SHAREPOINT_FOLDER_PATH=Your Folder Name
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 4. Use in your app
|
|
83
|
+
|
|
84
|
+
#### Option A: Drop-in file browser (full UI)
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
"use client";
|
|
88
|
+
|
|
89
|
+
import { useEffect } from "react";
|
|
90
|
+
import { useFiles, AuthBar, FileBrowser } from "team-connect";
|
|
91
|
+
|
|
92
|
+
export default function Page() {
|
|
93
|
+
const fileState = useFiles();
|
|
94
|
+
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
fileState.checkConnection().then((ok) => {
|
|
97
|
+
if (ok) fileState.fetchFiles("");
|
|
98
|
+
});
|
|
99
|
+
}, []);
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<div>
|
|
103
|
+
<AuthBar proxyConnected={fileState.proxyConnected} />
|
|
104
|
+
<FileBrowser fileState={fileState} />
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### Option B: Headless — just the hook
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
"use client";
|
|
114
|
+
|
|
115
|
+
import { useFiles } from "team-connect";
|
|
116
|
+
|
|
117
|
+
export default function MyComponent() {
|
|
118
|
+
const {
|
|
119
|
+
files,
|
|
120
|
+
loading,
|
|
121
|
+
currentPath,
|
|
122
|
+
proxyConnected,
|
|
123
|
+
checkConnection,
|
|
124
|
+
fetchFiles,
|
|
125
|
+
uploadFile,
|
|
126
|
+
createNewFolder,
|
|
127
|
+
deleteFile,
|
|
128
|
+
downloadFile,
|
|
129
|
+
search,
|
|
130
|
+
} = useFiles();
|
|
131
|
+
|
|
132
|
+
// Build your own UI using the file state and actions
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### Option C: Direct API (no React)
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
import {
|
|
140
|
+
checkProxyHealth,
|
|
141
|
+
listFiles,
|
|
142
|
+
uploadFile,
|
|
143
|
+
downloadFile,
|
|
144
|
+
createFolder,
|
|
145
|
+
deleteItem,
|
|
146
|
+
searchFiles,
|
|
147
|
+
} from "team-connect";
|
|
148
|
+
|
|
149
|
+
// Check proxy is running
|
|
150
|
+
const ok = await checkProxyHealth();
|
|
151
|
+
|
|
152
|
+
// List files in a subfolder
|
|
153
|
+
const files = await listFiles("Reports/Q1");
|
|
154
|
+
|
|
155
|
+
// Upload a file
|
|
156
|
+
await uploadFile(myFile, "Reports/Q1");
|
|
157
|
+
|
|
158
|
+
// Download
|
|
159
|
+
await downloadFile("/sites/MySite/Shared Documents/report.pdf", "report.pdf");
|
|
160
|
+
|
|
161
|
+
// Create folder
|
|
162
|
+
await createFolder("Q2", "Reports");
|
|
163
|
+
|
|
164
|
+
// Delete
|
|
165
|
+
await deleteItem("/sites/MySite/Shared Documents/old.xlsx", false);
|
|
166
|
+
|
|
167
|
+
// Search
|
|
168
|
+
const results = await searchFiles("invoice");
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Components
|
|
174
|
+
|
|
175
|
+
| Component | Props | Description |
|
|
176
|
+
|-----------|-------|-------------|
|
|
177
|
+
| `AuthBar` | `proxyConnected: boolean \| null` | Top bar with connection status indicator (green/yellow/red) |
|
|
178
|
+
| `FileBrowser` | `fileState: UseFilesReturn` | Full file browser with breadcrumbs, search, upload zone, file list |
|
|
179
|
+
| `FileList` | `files, loading, onFolderClick, onDownload, onDelete` | Table of files and folders with actions |
|
|
180
|
+
| `Breadcrumbs` | `items: BreadcrumbItem[], onNavigate` | Clickable path breadcrumbs |
|
|
181
|
+
| `SearchBar` | `onSearch, onClear` | Debounced search input |
|
|
182
|
+
| `UploadZone` | `onUpload, uploading?` | Drag-and-drop file upload area |
|
|
183
|
+
|
|
184
|
+
All components use Tailwind CSS classes. Make sure Tailwind is configured in your project.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Hook: `useFiles()`
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
|
|
192
|
+
| Property | Type | Description |
|
|
193
|
+
|----------|------|-------------|
|
|
194
|
+
| `files` | `FileItem[]` | Current file listing |
|
|
195
|
+
| `loading` | `boolean` | Loading state |
|
|
196
|
+
| `currentPath` | `string` | Current subfolder path |
|
|
197
|
+
| `proxyConnected` | `boolean \| null` | Proxy status (`null` = checking) |
|
|
198
|
+
| `checkConnection()` | `() => Promise<boolean>` | Ping the proxy health endpoint |
|
|
199
|
+
| `fetchFiles(path)` | `(path: string) => Promise<void>` | Load files at path |
|
|
200
|
+
| `uploadFile(file, path)` | `(file: File, path: string) => Promise<void>` | Upload a file |
|
|
201
|
+
| `createNewFolder(name, path)` | `(name: string, path: string) => Promise<void>` | Create a folder |
|
|
202
|
+
| `deleteFile(url, name, isFolder)` | `(...) => Promise<void>` | Delete a file or folder |
|
|
203
|
+
| `downloadFile(url, name)` | `(...) => Promise<void>` | Download a file |
|
|
204
|
+
| `search(query)` | `(query: string) => Promise<void>` | Search files by name |
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Types
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
interface FileItem {
|
|
212
|
+
id: string;
|
|
213
|
+
name: string;
|
|
214
|
+
size: number;
|
|
215
|
+
lastModifiedDateTime: string;
|
|
216
|
+
lastModifiedBy: { displayName: string; email?: string };
|
|
217
|
+
webUrl: string;
|
|
218
|
+
serverRelativeUrl: string;
|
|
219
|
+
isFolder: boolean;
|
|
220
|
+
mimeType?: string;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
interface BreadcrumbItem {
|
|
224
|
+
name: string;
|
|
225
|
+
path: string;
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Proxy API
|
|
232
|
+
|
|
233
|
+
The Go proxy exposes two endpoints:
|
|
234
|
+
|
|
235
|
+
| Endpoint | Description |
|
|
236
|
+
|----------|-------------|
|
|
237
|
+
| `GET /health` | Returns `{ status, siteUrl, serverRelativeUrl }` |
|
|
238
|
+
| `* /sp/…` | Proxies any request to `{siteUrl}/…` with auth injected |
|
|
239
|
+
|
|
240
|
+
### Proxy flags
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
./proxy --strategy ondemand --config ./config/private.json --port 8080
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
| Flag | Default | Description |
|
|
247
|
+
|------|---------|-------------|
|
|
248
|
+
| `--strategy` | `ondemand` | gosip auth strategy |
|
|
249
|
+
| `--config` | `./config/private.json` | Path to auth config |
|
|
250
|
+
| `--port` | `8080` | Proxy listen port |
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Styling
|
|
255
|
+
|
|
256
|
+
Components use Tailwind CSS utility classes. Ensure your project has Tailwind configured. The components use only standard Tailwind classes — no custom theme extensions required.
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Project structure
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
team-connect/
|
|
264
|
+
├── index.ts # Library entry point
|
|
265
|
+
├── types/index.ts # TypeScript types
|
|
266
|
+
├── lib/
|
|
267
|
+
│ ├── sp-client.ts # SharePoint REST API client
|
|
268
|
+
│ └── utils.ts # Formatting helpers
|
|
269
|
+
├── hooks/
|
|
270
|
+
│ └── useFiles.ts # React hook
|
|
271
|
+
├── components/
|
|
272
|
+
│ ├── AuthBar.tsx # Connection status bar
|
|
273
|
+
│ ├── Breadcrumbs.tsx # Path navigation
|
|
274
|
+
│ ├── FileBrowser.tsx # Main file browser
|
|
275
|
+
│ ├── FileList.tsx # File table
|
|
276
|
+
│ ├── SearchBar.tsx # Search input
|
|
277
|
+
│ └── UploadZone.tsx # Drag-and-drop upload
|
|
278
|
+
├── proxy/
|
|
279
|
+
│ ├── main.go # Go proxy server
|
|
280
|
+
│ ├── go.mod
|
|
281
|
+
│ └── config/
|
|
282
|
+
│ └── private.json # SharePoint site URL
|
|
283
|
+
├── app/ # Demo Next.js app
|
|
284
|
+
│ ├── page.tsx
|
|
285
|
+
│ └── layout.tsx
|
|
286
|
+
└── smoke-test.sh # Connectivity test
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Running the demo app
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
# Terminal 1: Start the proxy
|
|
295
|
+
cd proxy && ./team-connect-proxy
|
|
296
|
+
|
|
297
|
+
# Terminal 2: Start Next.js
|
|
298
|
+
npm run dev
|
|
299
|
+
# Open http://localhost:3000
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Smoke test
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
# With the proxy running:
|
|
308
|
+
bash smoke-test.sh
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## License
|
|
314
|
+
|
|
315
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthBar.d.ts","sourceRoot":"","sources":["../../components/AuthBar.tsx"],"names":[],"mappings":"AAGA,UAAU,YAAY;IACpB,cAAc,EAAE,OAAO,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,EAAE,cAAc,EAAE,EAAE,YAAY,2CA+B/D"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
export default function AuthBar({ proxyConnected }) {
|
|
4
|
+
const statusColor = proxyConnected === null
|
|
5
|
+
? "bg-yellow-400"
|
|
6
|
+
: proxyConnected
|
|
7
|
+
? "bg-green-400"
|
|
8
|
+
: "bg-red-500";
|
|
9
|
+
const statusLabel = proxyConnected === null
|
|
10
|
+
? "Checking…"
|
|
11
|
+
: proxyConnected
|
|
12
|
+
? "Connected"
|
|
13
|
+
: "Disconnected";
|
|
14
|
+
return (_jsxs("div", { className: "flex items-center justify-between px-6 py-3 bg-gray-900 text-white", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("h1", { className: "text-lg font-semibold tracking-tight", children: "Team Connect" }), _jsx("span", { className: "text-gray-400 text-sm", children: "|" }), _jsx("span", { className: "text-gray-400 text-sm", children: process.env.NEXT_PUBLIC_SHAREPOINT_FOLDER_PATH || "SharePoint" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: `w-2.5 h-2.5 rounded-full ${statusColor}` }), _jsx("span", { className: "text-sm text-gray-300", children: statusLabel })] })] }));
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=AuthBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthBar.js","sourceRoot":"","sources":["../../components/AuthBar.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAOb,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,EAAE,cAAc,EAAgB;IAC9D,MAAM,WAAW,GACf,cAAc,KAAK,IAAI;QACrB,CAAC,CAAC,eAAe;QACjB,CAAC,CAAC,cAAc;YAChB,CAAC,CAAC,cAAc;YAChB,CAAC,CAAC,YAAY,CAAC;IAEnB,MAAM,WAAW,GACf,cAAc,KAAK,IAAI;QACrB,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,cAAc;YAChB,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,cAAc,CAAC;IAErB,OAAO,CACL,eAAK,SAAS,EAAC,oEAAoE,aACjF,eAAK,SAAS,EAAC,yBAAyB,aACtC,aAAI,SAAS,EAAC,sCAAsC,6BAAkB,EACtE,eAAM,SAAS,EAAC,uBAAuB,kBAAS,EAChD,eAAM,SAAS,EAAC,uBAAuB,YACpC,OAAO,CAAC,GAAG,CAAC,kCAAkC,IAAI,YAAY,GAC1D,IACH,EAEN,eAAK,SAAS,EAAC,yBAAyB,aACtC,eAAM,SAAS,EAAE,4BAA4B,WAAW,EAAE,GAAI,EAC9D,eAAM,SAAS,EAAC,uBAAuB,YAAE,WAAW,GAAQ,IACxD,IACF,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BreadcrumbItem } from "../types";
|
|
2
|
+
interface BreadcrumbsProps {
|
|
3
|
+
items: BreadcrumbItem[];
|
|
4
|
+
onNavigate: (path: string) => void;
|
|
5
|
+
}
|
|
6
|
+
export default function Breadcrumbs({ items, onNavigate }: BreadcrumbsProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=Breadcrumbs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Breadcrumbs.d.ts","sourceRoot":"","sources":["../../components/Breadcrumbs.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1C,UAAU,gBAAgB;IACxB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,gBAAgB,2CAoB1E"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
export default function Breadcrumbs({ items, onNavigate }) {
|
|
4
|
+
return (_jsx("nav", { className: "flex items-center gap-1 text-sm text-gray-600 py-3 px-1 overflow-x-auto", children: items.map((item, index) => (_jsxs("span", { className: "flex items-center gap-1 whitespace-nowrap", children: [index > 0 && _jsx("span", { className: "text-gray-400 mx-1", children: "/" }), index === items.length - 1 ? (_jsx("span", { className: "font-medium text-gray-900", children: item.name })) : (_jsx("button", { onClick: () => onNavigate(item.path), className: "text-blue-600 hover:text-blue-800 hover:underline transition-colors", children: item.name }))] }, item.path))) }));
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=Breadcrumbs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Breadcrumbs.js","sourceRoot":"","sources":["../../components/Breadcrumbs.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AASb,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAAE,KAAK,EAAE,UAAU,EAAoB;IACzE,OAAO,CACL,cAAK,SAAS,EAAC,yEAAyE,YACrF,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC1B,gBAAsB,SAAS,EAAC,2CAA2C,aACxE,KAAK,GAAG,CAAC,IAAI,eAAM,SAAS,EAAC,oBAAoB,kBAAS,EAC1D,KAAK,KAAK,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAC5B,eAAM,SAAS,EAAC,2BAA2B,YAAE,IAAI,CAAC,IAAI,GAAQ,CAC/D,CAAC,CAAC,CAAC,CACF,iBACE,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EACpC,SAAS,EAAC,qEAAqE,YAE9E,IAAI,CAAC,IAAI,GACH,CACV,KAXQ,IAAI,CAAC,IAAI,CAYb,CACR,CAAC,GACE,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { UseFilesReturn } from "../hooks/useFiles";
|
|
2
|
+
interface FileBrowserProps {
|
|
3
|
+
fileState: UseFilesReturn;
|
|
4
|
+
}
|
|
5
|
+
export default function FileBrowser({ fileState }: FileBrowserProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=FileBrowser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileBrowser.d.ts","sourceRoot":"","sources":["../../components/FileBrowser.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAOnD,UAAU,gBAAgB;IACxB,SAAS,EAAE,cAAc,CAAC;CAC3B;AAED,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,gBAAgB,2CA4IlE"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useCallback } from "react";
|
|
4
|
+
import { buildBreadcrumbs } from "../lib/utils";
|
|
5
|
+
import Breadcrumbs from "./Breadcrumbs";
|
|
6
|
+
import SearchBar from "./SearchBar";
|
|
7
|
+
import FileList from "./FileList";
|
|
8
|
+
import UploadZone from "./UploadZone";
|
|
9
|
+
export default function FileBrowser({ fileState }) {
|
|
10
|
+
const { files, loading, currentPath, proxyConnected, fetchFiles, uploadFile, createNewFolder, deleteFile, downloadFile, search, } = fileState;
|
|
11
|
+
const [uploading, setUploading] = useState(false);
|
|
12
|
+
const [showNewFolder, setShowNewFolder] = useState(false);
|
|
13
|
+
const [newFolderName, setNewFolderName] = useState("");
|
|
14
|
+
const handleFolderClick = useCallback((folderName) => {
|
|
15
|
+
const newPath = currentPath ? `${currentPath}/${folderName}` : folderName;
|
|
16
|
+
fetchFiles(newPath);
|
|
17
|
+
}, [currentPath, fetchFiles]);
|
|
18
|
+
const handleBreadcrumbNavigate = useCallback((path) => {
|
|
19
|
+
fetchFiles(path);
|
|
20
|
+
}, [fetchFiles]);
|
|
21
|
+
const handleUpload = useCallback(async (uploadedFiles) => {
|
|
22
|
+
setUploading(true);
|
|
23
|
+
for (const file of uploadedFiles) {
|
|
24
|
+
await uploadFile(file, currentPath);
|
|
25
|
+
}
|
|
26
|
+
setUploading(false);
|
|
27
|
+
}, [uploadFile, currentPath]);
|
|
28
|
+
const handleCreateFolder = useCallback(async () => {
|
|
29
|
+
if (!newFolderName.trim())
|
|
30
|
+
return;
|
|
31
|
+
await createNewFolder(newFolderName.trim(), currentPath);
|
|
32
|
+
setNewFolderName("");
|
|
33
|
+
setShowNewFolder(false);
|
|
34
|
+
}, [newFolderName, createNewFolder, currentPath]);
|
|
35
|
+
const handleSearchClear = useCallback(() => {
|
|
36
|
+
fetchFiles(currentPath);
|
|
37
|
+
}, [fetchFiles, currentPath]);
|
|
38
|
+
if (proxyConnected === false) {
|
|
39
|
+
return (_jsxs("div", { className: "flex flex-col items-center justify-center py-24 text-gray-500", children: [_jsx("svg", { className: "w-16 h-16 mb-4 text-gray-300", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" }) }), _jsx("h2", { className: "text-xl font-semibold text-gray-700", children: "Proxy not connected" }), _jsxs("p", { className: "mt-2 text-sm max-w-md text-center", children: ["Start the Go proxy first:", _jsx("code", { className: "block mt-2 px-3 py-1 bg-gray-100 rounded text-xs text-gray-700 font-mono", children: "cd proxy && ./team-connect-proxy" })] })] }));
|
|
40
|
+
}
|
|
41
|
+
const breadcrumbs = buildBreadcrumbs(currentPath);
|
|
42
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-col sm:flex-row gap-3 items-start sm:items-center justify-between", children: [_jsx(Breadcrumbs, { items: breadcrumbs, onNavigate: handleBreadcrumbNavigate }), _jsxs("div", { className: "flex items-center gap-2 w-full sm:w-auto", children: [_jsx("div", { className: "flex-1 sm:w-64", children: _jsx(SearchBar, { onSearch: search, onClear: handleSearchClear }) }), _jsx("button", { onClick: () => setShowNewFolder(!showNewFolder), className: "px-3 py-2 text-sm bg-gray-100 hover:bg-gray-200 rounded-lg transition-colors whitespace-nowrap", children: "+ Folder" })] })] }), showNewFolder && (_jsxs("div", { className: "flex items-center gap-2 p-3 bg-gray-50 rounded-lg", children: [_jsx("input", { type: "text", value: newFolderName, onChange: (e) => setNewFolderName(e.target.value), onKeyDown: (e) => e.key === "Enter" && handleCreateFolder(), placeholder: "Folder name...", className: "flex-1 px-3 py-1.5 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500", autoFocus: true }), _jsx("button", { onClick: handleCreateFolder, className: "px-3 py-1.5 text-sm bg-blue-600 text-white rounded-md hover:bg-blue-500 transition-colors", children: "Create" }), _jsx("button", { onClick: () => {
|
|
43
|
+
setShowNewFolder(false);
|
|
44
|
+
setNewFolderName("");
|
|
45
|
+
}, className: "px-3 py-1.5 text-sm text-gray-600 hover:text-gray-800 transition-colors", children: "Cancel" })] })), _jsx(UploadZone, { onUpload: handleUpload, uploading: uploading }), _jsx(FileList, { files: files, loading: loading, onFolderClick: handleFolderClick, onDownload: downloadFile, onDelete: deleteFile })] }));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=FileBrowser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileBrowser.js","sourceRoot":"","sources":["../../components/FileBrowser.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAE9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,WAAW,MAAM,eAAe,CAAC;AACxC,OAAO,SAAS,MAAM,aAAa,CAAC;AACpC,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,UAAU,MAAM,cAAc,CAAC;AAMtC,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAAE,SAAS,EAAoB;IACjE,MAAM,EACJ,KAAK,EACL,OAAO,EACP,WAAW,EACX,cAAc,EACd,UAAU,EACV,UAAU,EACV,eAAe,EACf,UAAU,EACV,YAAY,EACZ,MAAM,GACP,GAAG,SAAS,CAAC;IAEd,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1D,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEvD,MAAM,iBAAiB,GAAG,WAAW,CACnC,CAAC,UAAkB,EAAE,EAAE;QACrB,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;QAC1E,UAAU,CAAC,OAAO,CAAC,CAAC;IACtB,CAAC,EACD,CAAC,WAAW,EAAE,UAAU,CAAC,CAC1B,CAAC;IAEF,MAAM,wBAAwB,GAAG,WAAW,CAC1C,CAAC,IAAY,EAAE,EAAE;QACf,UAAU,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,EACD,CAAC,UAAU,CAAC,CACb,CAAC;IAEF,MAAM,YAAY,GAAG,WAAW,CAC9B,KAAK,EAAE,aAAqB,EAAE,EAAE;QAC9B,YAAY,CAAC,IAAI,CAAC,CAAC;QACnB,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;YACjC,MAAM,UAAU,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACtC,CAAC;QACD,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC,EACD,CAAC,UAAU,EAAE,WAAW,CAAC,CAC1B,CAAC;IAEF,MAAM,kBAAkB,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAChD,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;YAAE,OAAO;QAClC,MAAM,eAAe,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,WAAW,CAAC,CAAC;QACzD,gBAAgB,CAAC,EAAE,CAAC,CAAC;QACrB,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC,EAAE,CAAC,aAAa,EAAE,eAAe,EAAE,WAAW,CAAC,CAAC,CAAC;IAElD,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAG,EAAE;QACzC,UAAU,CAAC,WAAW,CAAC,CAAC;IAC1B,CAAC,EAAE,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;IAE9B,IAAI,cAAc,KAAK,KAAK,EAAE,CAAC;QAC7B,OAAO,CACL,eAAK,SAAS,EAAC,+DAA+D,aAC5E,cAAK,SAAS,EAAC,8BAA8B,EAAC,IAAI,EAAC,MAAM,EAAC,MAAM,EAAC,cAAc,EAAC,OAAO,EAAC,WAAW,YACjG,eACE,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EACtB,WAAW,EAAE,GAAG,EAChB,CAAC,EAAC,sGAAsG,GACxG,GACE,EACN,aAAI,SAAS,EAAC,qCAAqC,oCAAyB,EAC5E,aAAG,SAAS,EAAC,mCAAmC,0CAE9C,eAAM,SAAS,EAAC,0EAA0E,iDAEnF,IACL,IACA,CACP,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAElD,OAAO,CACL,eAAK,SAAS,EAAC,WAAW,aAExB,eAAK,SAAS,EAAC,6EAA6E,aAC1F,KAAC,WAAW,IAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,wBAAwB,GAAI,EACzE,eAAK,SAAS,EAAC,0CAA0C,aACvD,cAAK,SAAS,EAAC,gBAAgB,YAC7B,KAAC,SAAS,IAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAI,GACvD,EACN,iBACE,OAAO,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,CAAC,aAAa,CAAC,EAC/C,SAAS,EAAC,gGAAgG,yBAGnG,IACL,IACF,EAGL,aAAa,IAAI,CAChB,eAAK,SAAS,EAAC,mDAAmD,aAChE,gBACE,IAAI,EAAC,MAAM,EACX,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACjD,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,kBAAkB,EAAE,EAC3D,WAAW,EAAC,gBAAgB,EAC5B,SAAS,EAAC,kHAAkH,EAC5H,SAAS,SACT,EACF,iBACE,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAC,2FAA2F,uBAG9F,EACT,iBACE,OAAO,EAAE,GAAG,EAAE;4BACZ,gBAAgB,CAAC,KAAK,CAAC,CAAC;4BACxB,gBAAgB,CAAC,EAAE,CAAC,CAAC;wBACvB,CAAC,EACD,SAAS,EAAC,yEAAyE,uBAG5E,IACL,CACP,EAGD,KAAC,UAAU,IAAC,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,GAAI,EAG5D,KAAC,QAAQ,IACP,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,iBAAiB,EAChC,UAAU,EAAE,YAAY,EACxB,QAAQ,EAAE,UAAU,GACpB,IACE,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FileItem } from "../types";
|
|
2
|
+
interface FileListProps {
|
|
3
|
+
files: FileItem[];
|
|
4
|
+
loading: boolean;
|
|
5
|
+
onFolderClick: (folderName: string) => void;
|
|
6
|
+
onDownload: (serverRelativeUrl: string, fileName: string) => void;
|
|
7
|
+
onDelete: (serverRelativeUrl: string, itemName: string, isFolder: boolean) => void;
|
|
8
|
+
}
|
|
9
|
+
export default function FileList({ files, loading, onFolderClick, onDownload, onDelete, }: FileListProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=FileList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileList.d.ts","sourceRoot":"","sources":["../../components/FileList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGpC,UAAU,aAAa;IACrB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,UAAU,EAAE,CAAC,iBAAiB,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAClE,QAAQ,EAAE,CAAC,iBAAiB,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;CACpF;AAED,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,EAC/B,KAAK,EACL,OAAO,EACP,aAAa,EACb,UAAU,EACV,QAAQ,GACT,EAAE,aAAa,2CAkIf"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { formatFileSize, formatDate, getFileIcon } from "../lib/utils";
|
|
4
|
+
export default function FileList({ files, loading, onFolderClick, onDownload, onDelete, }) {
|
|
5
|
+
if (loading) {
|
|
6
|
+
return (_jsx("div", { className: "flex items-center justify-center py-12", children: _jsxs("svg", { className: "animate-spin w-8 h-8 text-blue-500", fill: "none", viewBox: "0 0 24 24", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })] }) }));
|
|
7
|
+
}
|
|
8
|
+
if (files.length === 0) {
|
|
9
|
+
return (_jsxs("div", { className: "text-center py-12 text-gray-500", children: [_jsx("p", { className: "text-lg", children: "No files found" }), _jsx("p", { className: "text-sm mt-1", children: "Upload files or create a folder to get started" })] }));
|
|
10
|
+
}
|
|
11
|
+
// Sort folders first, then files
|
|
12
|
+
const sorted = [...files].sort((a, b) => {
|
|
13
|
+
if (a.isFolder && !b.isFolder)
|
|
14
|
+
return -1;
|
|
15
|
+
if (!a.isFolder && b.isFolder)
|
|
16
|
+
return 1;
|
|
17
|
+
return a.name.localeCompare(b.name);
|
|
18
|
+
});
|
|
19
|
+
return (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { children: _jsxs("tr", { className: "border-b border-gray-200 text-left text-gray-500", children: [_jsx("th", { className: "py-2 px-3 font-medium", children: "Name" }), _jsx("th", { className: "py-2 px-3 font-medium w-24", children: "Size" }), _jsx("th", { className: "py-2 px-3 font-medium w-44", children: "Modified" }), _jsx("th", { className: "py-2 px-3 font-medium w-36", children: "Modified by" }), _jsx("th", { className: "py-2 px-3 font-medium w-24 text-right", children: "Actions" })] }) }), _jsx("tbody", { children: sorted.map((file) => (_jsxs("tr", { className: "border-b border-gray-100 hover:bg-gray-50 transition-colors", children: [_jsx("td", { className: "py-2.5 px-3", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-base", children: getFileIcon(file.name, file.isFolder) }), file.isFolder ? (_jsx("button", { onClick: () => onFolderClick(file.name), className: "text-blue-600 hover:text-blue-800 hover:underline font-medium", children: file.name })) : (_jsx("button", { onClick: () => onDownload(file.serverRelativeUrl, file.name), className: "text-gray-900 hover:text-blue-600 hover:underline", children: file.name }))] }) }), _jsx("td", { className: "py-2.5 px-3 text-gray-500", children: file.isFolder ? "—" : formatFileSize(file.size) }), _jsx("td", { className: "py-2.5 px-3 text-gray-500", children: formatDate(file.lastModifiedDateTime) }), _jsx("td", { className: "py-2.5 px-3 text-gray-500 truncate max-w-[140px]", children: file.lastModifiedBy.displayName }), _jsx("td", { className: "py-2.5 px-3 text-right", children: _jsxs("div", { className: "flex items-center justify-end gap-1", children: [!file.isFolder && (_jsx("button", { onClick: () => onDownload(file.serverRelativeUrl, file.name), className: "p-1.5 text-gray-400 hover:text-blue-600 rounded transition-colors", title: "Download", children: _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) }) })), _jsx("button", { onClick: () => {
|
|
20
|
+
if (confirm(`Delete "${file.name}"?`)) {
|
|
21
|
+
onDelete(file.serverRelativeUrl, file.name, file.isFolder);
|
|
22
|
+
}
|
|
23
|
+
}, className: "p-1.5 text-gray-400 hover:text-red-600 rounded transition-colors", title: "Delete", children: _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" }) }) })] }) })] }, file.id))) })] }) }));
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=FileList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileList.js","sourceRoot":"","sources":["../../components/FileList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchBar.d.ts","sourceRoot":"","sources":["../../components/SearchBar.tsx"],"names":[],"mappings":"AAIA,UAAU,cAAc;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,cAAc,2CA4DtE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useRef } from "react";
|
|
4
|
+
export default function SearchBar({ onSearch, onClear }) {
|
|
5
|
+
const [query, setQuery] = useState("");
|
|
6
|
+
const debounceRef = useRef(null);
|
|
7
|
+
const handleChange = (value) => {
|
|
8
|
+
setQuery(value);
|
|
9
|
+
if (debounceRef.current)
|
|
10
|
+
clearTimeout(debounceRef.current);
|
|
11
|
+
if (!value.trim()) {
|
|
12
|
+
onClear();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
debounceRef.current = setTimeout(() => {
|
|
16
|
+
onSearch(value);
|
|
17
|
+
}, 400);
|
|
18
|
+
};
|
|
19
|
+
const handleSubmit = (e) => {
|
|
20
|
+
e.preventDefault();
|
|
21
|
+
if (query.trim())
|
|
22
|
+
onSearch(query);
|
|
23
|
+
};
|
|
24
|
+
return (_jsxs("form", { onSubmit: handleSubmit, className: "relative", children: [_jsx("input", { type: "text", value: query, onChange: (e) => handleChange(e.target.value), placeholder: "Search files...", className: "w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" }), _jsx("svg", { className: "absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), query && (_jsx("button", { type: "button", onClick: () => {
|
|
25
|
+
setQuery("");
|
|
26
|
+
onClear();
|
|
27
|
+
}, className: "absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600", children: "\u2715" }))] }));
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=SearchBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchBar.js","sourceRoot":"","sources":["../../components/SearchBar.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAOzC,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAkB;IACrE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,MAAM,CAAwB,IAAI,CAAC,CAAC;IAExD,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,EAAE;QACrC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAEhB,IAAI,WAAW,CAAC,OAAO;YAAE,YAAY,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAE3D,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QAED,WAAW,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YACpC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,CAAC,CAAkB,EAAE,EAAE;QAC1C,CAAC,CAAC,cAAc,EAAE,CAAC;QACnB,IAAI,KAAK,CAAC,IAAI,EAAE;YAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC,CAAC;IAEF,OAAO,CACL,gBAAM,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAC,UAAU,aAChD,gBACE,IAAI,EAAC,MAAM,EACX,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAC7C,WAAW,EAAC,iBAAiB,EAC7B,SAAS,EAAC,+IAA+I,GACzJ,EACF,cACE,SAAS,EAAC,gEAAgE,EAC1E,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,cAAc,EACrB,OAAO,EAAC,WAAW,YAEnB,eACE,aAAa,EAAC,OAAO,EACrB,cAAc,EAAC,OAAO,EACtB,WAAW,EAAE,CAAC,EACd,CAAC,EAAC,6CAA6C,GAC/C,GACE,EACL,KAAK,IAAI,CACR,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE;oBACZ,QAAQ,CAAC,EAAE,CAAC,CAAC;oBACb,OAAO,EAAE,CAAC;gBACZ,CAAC,EACD,SAAS,EAAC,6EAA6E,uBAGhF,CACV,IACI,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface UploadZoneProps {
|
|
2
|
+
onUpload: (files: File[]) => void;
|
|
3
|
+
uploading?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export default function UploadZone({ onUpload, uploading }: UploadZoneProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=UploadZone.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UploadZone.d.ts","sourceRoot":"","sources":["../../components/UploadZone.tsx"],"names":[],"mappings":"AAKA,UAAU,eAAe;IACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,eAAe,2CAyD1E"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback } from "react";
|
|
4
|
+
import { useDropzone } from "react-dropzone";
|
|
5
|
+
export default function UploadZone({ onUpload, uploading }) {
|
|
6
|
+
const onDrop = useCallback((acceptedFiles) => {
|
|
7
|
+
onUpload(acceptedFiles);
|
|
8
|
+
}, [onUpload]);
|
|
9
|
+
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
|
10
|
+
onDrop,
|
|
11
|
+
disabled: uploading,
|
|
12
|
+
});
|
|
13
|
+
return (_jsxs("div", Object.assign({}, getRootProps(), { className: `border-2 border-dashed rounded-lg p-6 text-center cursor-pointer transition-colors ${isDragActive
|
|
14
|
+
? "border-blue-500 bg-blue-50"
|
|
15
|
+
: uploading
|
|
16
|
+
? "border-gray-200 bg-gray-50 cursor-not-allowed"
|
|
17
|
+
: "border-gray-300 hover:border-blue-400 hover:bg-gray-50"}`, children: [_jsx("input", Object.assign({}, getInputProps())), uploading ? (_jsxs("div", { className: "flex items-center justify-center gap-2 text-gray-500", children: [_jsxs("svg", { className: "animate-spin w-5 h-5", fill: "none", viewBox: "0 0 24 24", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" })] }), _jsx("span", { className: "text-sm", children: "Uploading..." })] })) : isDragActive ? (_jsx("p", { className: "text-sm text-blue-600 font-medium", children: "Drop files here..." })) : (_jsxs("div", { children: [_jsxs("p", { className: "text-sm text-gray-600", children: ["Drag & drop files here, or", " ", _jsx("span", { className: "text-blue-600 font-medium", children: "browse" })] }), _jsx("p", { className: "text-xs text-gray-400 mt-1", children: "Any file type supported" })] }))] })));
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=UploadZone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UploadZone.js","sourceRoot":"","sources":["../../components/UploadZone.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAO7C,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAmB;IACzE,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,aAAqB,EAAE,EAAE;QACxB,QAAQ,CAAC,aAAa,CAAC,CAAC;IAC1B,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,WAAW,CAAC;QAChE,MAAM;QACN,QAAQ,EAAE,SAAS;KACpB,CAAC,CAAC;IAEH,OAAO,CACL,+BACM,YAAY,EAAE,IAClB,SAAS,EAAE,sFACT,YAAY;YACV,CAAC,CAAC,4BAA4B;YAC9B,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,+CAA+C;gBACjD,CAAC,CAAC,wDACN,EAAE,aAEF,gCAAW,aAAa,EAAE,EAAI,EAC7B,SAAS,CAAC,CAAC,CAAC,CACX,eAAK,SAAS,EAAC,sDAAsD,aACnE,eAAK,SAAS,EAAC,sBAAsB,EAAC,IAAI,EAAC,MAAM,EAAC,OAAO,EAAC,WAAW,aACnE,iBACE,SAAS,EAAC,YAAY,EACtB,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAC,IAAI,EACN,MAAM,EAAC,cAAc,EACrB,WAAW,EAAC,GAAG,GACf,EACF,eACE,SAAS,EAAC,YAAY,EACtB,IAAI,EAAC,cAAc,EACnB,CAAC,EAAC,6CAA6C,GAC/C,IACE,EACN,eAAM,SAAS,EAAC,SAAS,6BAAoB,IACzC,CACP,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CACjB,YAAG,SAAS,EAAC,mCAAmC,mCAAuB,CACxE,CAAC,CAAC,CAAC,CACF,0BACE,aAAG,SAAS,EAAC,uBAAuB,2CACP,GAAG,EAC9B,eAAM,SAAS,EAAC,2BAA2B,uBAAc,IACvD,EACJ,YAAG,SAAS,EAAC,4BAA4B,wCAA4B,IACjE,CACP,KACG,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FileItem } from "../types";
|
|
2
|
+
export declare function useFiles(): {
|
|
3
|
+
files: FileItem[];
|
|
4
|
+
loading: boolean;
|
|
5
|
+
currentPath: string;
|
|
6
|
+
proxyConnected: boolean | null;
|
|
7
|
+
checkConnection: () => Promise<boolean>;
|
|
8
|
+
fetchFiles: (path?: string) => Promise<void>;
|
|
9
|
+
uploadFile: (file: File, path: string) => Promise<void>;
|
|
10
|
+
createNewFolder: (folderName: string, path: string) => Promise<void>;
|
|
11
|
+
deleteFile: (serverRelativeUrl: string, itemName: string, isFolder: boolean) => Promise<void>;
|
|
12
|
+
downloadFile: (serverRelativeUrl: string, fileName: string) => Promise<void>;
|
|
13
|
+
search: (query: string) => Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
export type UseFilesReturn = ReturnType<typeof useFiles>;
|
|
16
|
+
//# sourceMappingURL=useFiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFiles.d.ts","sourceRoot":"","sources":["../../hooks/useFiles.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAYpC,wBAAgB,QAAQ;;;;;2BAMwB,OAAO,CAAC,OAAO,CAAC;wBAMlB,MAAM;uBAcnC,IAAI,QAAQ,MAAM;kCAaZ,MAAM,QAAQ,MAAM;oCAeb,MAAM,YAAY,MAAM,YAAY,OAAO;sCAa3C,MAAM,YAAY,MAAM;oBAYpC,MAAM;EA+BvB;AAED,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC"}
|