@gallop.software/studio 0.1.88 → 0.1.90

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.
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-HXE6XCG2.mjs";
8
8
 
9
9
  // src/components/StudioUI.tsx
10
- import { useEffect as useEffect3, useCallback as useCallback3, useState as useState9 } from "react";
10
+ import { useEffect as useEffect4, useCallback as useCallback3, useState as useState9 } from "react";
11
11
  import { css as css10 } from "@emotion/react";
12
12
 
13
13
  // src/components/StudioContext.tsx
@@ -50,6 +50,11 @@ var defaultState = {
50
50
  refreshKey: 0,
51
51
  triggerRefresh: () => {
52
52
  },
53
+ scanRequested: false,
54
+ triggerScan: () => {
55
+ },
56
+ clearScanRequest: () => {
57
+ },
53
58
  searchQuery: "",
54
59
  setSearchQuery: () => {
55
60
  },
@@ -65,7 +70,7 @@ function useStudio() {
65
70
  }
66
71
 
67
72
  // src/components/StudioToolbar.tsx
68
- import { useCallback, useRef, useState as useState3 } from "react";
73
+ import { useCallback, useEffect as useEffect2, useRef, useState as useState3 } from "react";
69
74
  import { css as css4, keyframes as keyframes3 } from "@emotion/react";
70
75
 
71
76
  // src/components/StudioModal.tsx
@@ -1285,11 +1290,11 @@ var styles4 = {
1285
1290
  `
1286
1291
  };
1287
1292
  function StudioToolbar() {
1288
- const { selectedItems, viewMode, setViewMode, clearSelection, currentPath, triggerRefresh, focusedItem } = useStudio();
1293
+ const { selectedItems, viewMode, setViewMode, clearSelection, currentPath, triggerRefresh, focusedItem, scanRequested, clearScanRequest } = useStudio();
1289
1294
  const fileInputRef = useRef(null);
1290
1295
  const abortControllerRef = useRef(null);
1291
1296
  const [uploading, setUploading] = useState3(false);
1292
- const [refreshing, setRefreshing] = useState3(false);
1297
+ const [scanning, setScanning] = useState3(false);
1293
1298
  const [processing, setProcessing] = useState3(false);
1294
1299
  const [showDeleteConfirm, setShowDeleteConfirm] = useState3(false);
1295
1300
  const [showProcessConfirm, setShowProcessConfirm] = useState3(false);
@@ -1315,11 +1320,88 @@ function StudioToolbar() {
1315
1320
  const handleUpload = useCallback(() => {
1316
1321
  fileInputRef.current?.click();
1317
1322
  }, []);
1318
- const handleRefresh = useCallback(() => {
1319
- setRefreshing(true);
1320
- triggerRefresh();
1321
- setTimeout(() => setRefreshing(false), 600);
1323
+ const handleScan = useCallback(async () => {
1324
+ setScanning(true);
1325
+ setShowProgress(true);
1326
+ setProgressState({
1327
+ current: 0,
1328
+ total: 0,
1329
+ percent: 0,
1330
+ status: "processing",
1331
+ message: "Scanning for files..."
1332
+ });
1333
+ try {
1334
+ const response = await fetch("/api/studio/scan", { method: "POST" });
1335
+ const reader = response.body?.getReader();
1336
+ if (!reader) throw new Error("No reader");
1337
+ const decoder = new TextDecoder();
1338
+ let buffer = "";
1339
+ while (true) {
1340
+ const { done, value } = await reader.read();
1341
+ if (done) break;
1342
+ buffer += decoder.decode(value, { stream: true });
1343
+ const lines = buffer.split("\n\n");
1344
+ buffer = lines.pop() || "";
1345
+ for (const line of lines) {
1346
+ if (!line.startsWith("data: ")) continue;
1347
+ const data = JSON.parse(line.slice(6));
1348
+ if (data.type === "start") {
1349
+ setProgressState({
1350
+ current: 0,
1351
+ total: data.total,
1352
+ percent: 0,
1353
+ status: "processing",
1354
+ message: `Scanning ${data.total} files...`
1355
+ });
1356
+ } else if (data.type === "progress") {
1357
+ setProgressState({
1358
+ current: data.current,
1359
+ total: data.total,
1360
+ percent: data.percent,
1361
+ status: "processing",
1362
+ currentFile: data.currentFile
1363
+ });
1364
+ } else if (data.type === "complete") {
1365
+ setProgressState({
1366
+ current: data.total || 0,
1367
+ total: data.total || 0,
1368
+ percent: 100,
1369
+ status: "complete",
1370
+ processed: data.added,
1371
+ errors: data.errors,
1372
+ message: data.renamed > 0 ? `${data.renamed} file(s) renamed due to conflicts` : void 0
1373
+ });
1374
+ triggerRefresh();
1375
+ } else if (data.type === "error") {
1376
+ setProgressState({
1377
+ current: 0,
1378
+ total: 0,
1379
+ percent: 0,
1380
+ status: "error",
1381
+ message: data.message || "Scan failed"
1382
+ });
1383
+ }
1384
+ }
1385
+ }
1386
+ } catch (error) {
1387
+ console.error("Scan error:", error);
1388
+ setProgressState({
1389
+ current: 0,
1390
+ total: 0,
1391
+ percent: 0,
1392
+ status: "error",
1393
+ message: "Scan failed"
1394
+ });
1395
+ } finally {
1396
+ setScanning(false);
1397
+ }
1322
1398
  }, [triggerRefresh]);
1399
+ useEffect2(() => {
1400
+ if (scanRequested && !scanning) {
1401
+ clearScanRequest();
1402
+ handleScan();
1403
+ }
1404
+ }, [scanRequested, scanning, clearScanRequest, handleScan]);
1323
1405
  const handleFileChange = useCallback(async (e) => {
1324
1406
  const files = e.target.files;
1325
1407
  if (!files || files.length === 0) return;
@@ -1903,8 +1985,8 @@ function StudioToolbar() {
1903
1985
  showSyncConfirm && /* @__PURE__ */ jsx4(
1904
1986
  ConfirmModal,
1905
1987
  {
1906
- title: "Sync to CDN",
1907
- message: `Sync ${syncImageCount} image${syncImageCount !== 1 ? "s" : ""} to Cloudflare R2? Images must be processed first. After syncing, local thumbnails will be deleted.`,
1988
+ title: "Push to CDN",
1989
+ message: `Push ${syncImageCount} image${syncImageCount !== 1 ? "s" : ""} to Cloudflare R2? Images must be processed first. After pushing, local files will be deleted.`,
1908
1990
  confirmLabel: "Sync",
1909
1991
  onConfirm: handleSyncConfirm,
1910
1992
  onCancel: () => setShowSyncConfirm(false)
@@ -2071,7 +2153,7 @@ function StudioToolbar() {
2071
2153
  disabled: !hasSelection,
2072
2154
  children: [
2073
2155
  /* @__PURE__ */ jsx4(CloudIcon, {}),
2074
- "Sync CDN"
2156
+ "Push CDN"
2075
2157
  ]
2076
2158
  }
2077
2159
  ),
@@ -2104,12 +2186,16 @@ function StudioToolbar() {
2104
2186
  " selected",
2105
2187
  /* @__PURE__ */ jsx4("button", { css: styles4.clearBtn, onClick: clearSelection, children: "Clear" })
2106
2188
  ] }),
2107
- /* @__PURE__ */ jsx4(
2189
+ /* @__PURE__ */ jsxs4(
2108
2190
  "button",
2109
2191
  {
2110
- css: [styles4.btn, styles4.btnIconOnly],
2111
- onClick: handleRefresh,
2112
- children: /* @__PURE__ */ jsx4(RefreshIcon, { spinning: refreshing })
2192
+ css: styles4.btn,
2193
+ onClick: handleScan,
2194
+ disabled: scanning,
2195
+ children: [
2196
+ /* @__PURE__ */ jsx4(ScanIcon, { spinning: scanning }),
2197
+ "Scan"
2198
+ ]
2113
2199
  }
2114
2200
  ),
2115
2201
  /* @__PURE__ */ jsxs4("div", { css: styles4.viewToggle, children: [
@@ -2139,7 +2225,7 @@ function StudioToolbar() {
2139
2225
  function UploadIcon() {
2140
2226
  return /* @__PURE__ */ jsx4("svg", { css: styles4.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" }) });
2141
2227
  }
2142
- function RefreshIcon({ spinning }) {
2228
+ function ScanIcon({ spinning }) {
2143
2229
  return /* @__PURE__ */ jsx4("svg", { css: [styles4.icon, spinning && styles4.iconSpin], fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" }) });
2144
2230
  }
2145
2231
  function TrashIcon() {
@@ -2172,7 +2258,7 @@ import { useState as useState5 } from "react";
2172
2258
  import { css as css5, keyframes as keyframes4 } from "@emotion/react";
2173
2259
 
2174
2260
  // src/hooks/useFileList.ts
2175
- import { useEffect as useEffect2, useState as useState4, useRef as useRef2, useCallback as useCallback2 } from "react";
2261
+ import { useEffect as useEffect3, useState as useState4, useRef as useRef2, useCallback as useCallback2 } from "react";
2176
2262
 
2177
2263
  // src/lib/api.ts
2178
2264
  var StudioApiClient = class {
@@ -2268,14 +2354,16 @@ function useFileList() {
2268
2354
  refreshKey,
2269
2355
  setFocusedItem,
2270
2356
  triggerRefresh,
2357
+ triggerScan,
2271
2358
  searchQuery,
2272
2359
  showError
2273
2360
  } = useStudio();
2274
2361
  const [items, setItems] = useState4([]);
2275
2362
  const [loading, setLoading] = useState4(true);
2363
+ const [metaEmpty, setMetaEmpty] = useState4(false);
2276
2364
  const isInitialLoad = useRef2(true);
2277
2365
  const lastPath = useRef2(currentPath);
2278
- useEffect2(() => {
2366
+ useEffect3(() => {
2279
2367
  async function loadItems() {
2280
2368
  const isPathChange = lastPath.current !== currentPath;
2281
2369
  if (isInitialLoad.current || isPathChange) {
@@ -2285,10 +2373,12 @@ function useFileList() {
2285
2373
  try {
2286
2374
  const data = searchQuery && searchQuery.length >= 2 ? await studioApi.search(searchQuery) : await studioApi.list(currentPath);
2287
2375
  setItems(data.items || []);
2376
+ setMetaEmpty(data.isEmpty === true);
2288
2377
  } catch (error) {
2289
2378
  const message = error instanceof Error ? error.message : "Failed to load items";
2290
2379
  showError("Load Error", message);
2291
2380
  setItems([]);
2381
+ setMetaEmpty(false);
2292
2382
  }
2293
2383
  setLoading(false);
2294
2384
  isInitialLoad.current = false;
@@ -2340,6 +2430,7 @@ function useFileList() {
2340
2430
  items,
2341
2431
  loading,
2342
2432
  sortedItems,
2433
+ metaEmpty,
2343
2434
  // Computed
2344
2435
  isAtRoot,
2345
2436
  isSearching,
@@ -2353,7 +2444,8 @@ function useFileList() {
2353
2444
  handleItemClick,
2354
2445
  handleOpen,
2355
2446
  handleGenerateThumbnail,
2356
- handleSelectAll
2447
+ handleSelectAll,
2448
+ triggerScan
2357
2449
  };
2358
2450
  }
2359
2451
 
@@ -2367,7 +2459,8 @@ var styles5 = {
2367
2459
  display: flex;
2368
2460
  align-items: center;
2369
2461
  justify-content: center;
2370
- height: 256px;
2462
+ flex: 1;
2463
+ min-height: 300px;
2371
2464
  `,
2372
2465
  spinner: css5`
2373
2466
  width: 32px;
@@ -2382,7 +2475,8 @@ var styles5 = {
2382
2475
  flex-direction: column;
2383
2476
  align-items: center;
2384
2477
  justify-content: center;
2385
- height: 256px;
2478
+ flex: 1;
2479
+ min-height: 300px;
2386
2480
  color: ${colors.textSecondary};
2387
2481
  `,
2388
2482
  emptyIcon: css5`
@@ -2400,6 +2494,27 @@ var styles5 = {
2400
2494
  font-size: ${fontSize.sm};
2401
2495
  }
2402
2496
  `,
2497
+ scanButton: css5`
2498
+ margin-top: 16px;
2499
+ padding: 10px 24px;
2500
+ font-size: ${fontSize.base};
2501
+ font-weight: 500;
2502
+ background: ${colors.primary};
2503
+ color: white;
2504
+ border: none;
2505
+ border-radius: 8px;
2506
+ cursor: pointer;
2507
+ transition: background 0.15s ease;
2508
+
2509
+ &:hover:not(:disabled) {
2510
+ background: ${colors.primaryHover};
2511
+ }
2512
+
2513
+ &:disabled {
2514
+ opacity: 0.6;
2515
+ cursor: not-allowed;
2516
+ }
2517
+ `,
2403
2518
  grid: css5`
2404
2519
  display: grid;
2405
2520
  grid-template-columns: 1fr;
@@ -2683,6 +2798,7 @@ function StudioFileGrid() {
2683
2798
  const {
2684
2799
  loading,
2685
2800
  sortedItems,
2801
+ metaEmpty,
2686
2802
  isAtRoot,
2687
2803
  isSearching,
2688
2804
  allItemsSelected,
@@ -2692,16 +2808,32 @@ function StudioFileGrid() {
2692
2808
  handleItemClick,
2693
2809
  handleOpen,
2694
2810
  handleGenerateThumbnail,
2695
- handleSelectAll
2811
+ handleSelectAll,
2812
+ triggerScan
2696
2813
  } = useFileList();
2697
2814
  if (loading) {
2698
2815
  return /* @__PURE__ */ jsx5("div", { css: styles5.loading, children: /* @__PURE__ */ jsx5("div", { css: styles5.spinner }) });
2699
2816
  }
2817
+ if (metaEmpty && isAtRoot) {
2818
+ return /* @__PURE__ */ jsxs5("div", { css: styles5.empty, children: [
2819
+ /* @__PURE__ */ jsx5("svg", { css: styles5.emptyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }),
2820
+ /* @__PURE__ */ jsx5("p", { css: styles5.emptyText, children: "No files tracked yet" }),
2821
+ /* @__PURE__ */ jsx5("p", { css: styles5.emptyText, children: "Click Scan to discover files in your public folder" }),
2822
+ /* @__PURE__ */ jsx5(
2823
+ "button",
2824
+ {
2825
+ css: styles5.scanButton,
2826
+ onClick: triggerScan,
2827
+ children: "Scan for Files"
2828
+ }
2829
+ )
2830
+ ] });
2831
+ }
2700
2832
  if (sortedItems.length === 0 && isAtRoot) {
2701
2833
  return /* @__PURE__ */ jsxs5("div", { css: styles5.empty, children: [
2702
2834
  /* @__PURE__ */ jsx5("svg", { css: styles5.emptyIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
2703
2835
  /* @__PURE__ */ jsx5("p", { css: styles5.emptyText, children: "No files in this folder" }),
2704
- /* @__PURE__ */ jsx5("p", { css: styles5.emptyText, children: "Upload images to get started" })
2836
+ /* @__PURE__ */ jsx5("p", { css: styles5.emptyText, children: "Upload images or click Scan in the toolbar" })
2705
2837
  ] });
2706
2838
  }
2707
2839
  return /* @__PURE__ */ jsxs5("div", { children: [
@@ -2880,7 +3012,8 @@ var styles6 = {
2880
3012
  display: flex;
2881
3013
  align-items: center;
2882
3014
  justify-content: center;
2883
- height: 256px;
3015
+ flex: 1;
3016
+ min-height: 300px;
2884
3017
  `,
2885
3018
  spinner: css6`
2886
3019
  width: 32px;
@@ -2895,9 +3028,36 @@ var styles6 = {
2895
3028
  flex-direction: column;
2896
3029
  align-items: center;
2897
3030
  justify-content: center;
2898
- height: 256px;
3031
+ flex: 1;
3032
+ min-height: 300px;
2899
3033
  color: ${colors.textSecondary};
2900
3034
  `,
3035
+ emptyHint: css6`
3036
+ font-size: ${fontSize.sm};
3037
+ color: ${colors.textMuted};
3038
+ margin-top: 4px;
3039
+ `,
3040
+ scanButton: css6`
3041
+ margin-top: 16px;
3042
+ padding: 10px 24px;
3043
+ font-size: ${fontSize.base};
3044
+ font-weight: 500;
3045
+ background: ${colors.primary};
3046
+ color: white;
3047
+ border: none;
3048
+ border-radius: 8px;
3049
+ cursor: pointer;
3050
+ transition: background 0.15s ease;
3051
+
3052
+ &:hover:not(:disabled) {
3053
+ background: ${colors.primaryHover};
3054
+ }
3055
+
3056
+ &:disabled {
3057
+ opacity: 0.6;
3058
+ cursor: not-allowed;
3059
+ }
3060
+ `,
2901
3061
  tableWrapper: css6`
2902
3062
  background: ${colors.surface};
2903
3063
  border-radius: 8px;
@@ -3184,6 +3344,7 @@ function StudioFileList() {
3184
3344
  const {
3185
3345
  loading,
3186
3346
  sortedItems,
3347
+ metaEmpty,
3187
3348
  isAtRoot,
3188
3349
  isSearching,
3189
3350
  allItemsSelected,
@@ -3193,13 +3354,31 @@ function StudioFileList() {
3193
3354
  handleItemClick,
3194
3355
  handleOpen,
3195
3356
  handleGenerateThumbnail,
3196
- handleSelectAll
3357
+ handleSelectAll,
3358
+ triggerScan
3197
3359
  } = useFileList();
3198
3360
  if (loading) {
3199
3361
  return /* @__PURE__ */ jsx6("div", { css: styles6.loading, children: /* @__PURE__ */ jsx6("div", { css: styles6.spinner }) });
3200
3362
  }
3363
+ if (metaEmpty && isAtRoot) {
3364
+ return /* @__PURE__ */ jsxs6("div", { css: styles6.empty, children: [
3365
+ /* @__PURE__ */ jsx6("p", { children: "No files tracked yet" }),
3366
+ /* @__PURE__ */ jsx6("p", { css: styles6.emptyHint, children: "Click Scan to discover files in your public folder" }),
3367
+ /* @__PURE__ */ jsx6(
3368
+ "button",
3369
+ {
3370
+ css: styles6.scanButton,
3371
+ onClick: triggerScan,
3372
+ children: "Scan for Files"
3373
+ }
3374
+ )
3375
+ ] });
3376
+ }
3201
3377
  if (sortedItems.length === 0 && isAtRoot) {
3202
- return /* @__PURE__ */ jsx6("div", { css: styles6.empty, children: /* @__PURE__ */ jsx6("p", { children: "No files in this folder" }) });
3378
+ return /* @__PURE__ */ jsxs6("div", { css: styles6.empty, children: [
3379
+ /* @__PURE__ */ jsx6("p", { children: "No files in this folder" }),
3380
+ /* @__PURE__ */ jsx6("p", { css: styles6.emptyHint, children: "Upload images or click Scan in the toolbar" })
3381
+ ] });
3203
3382
  }
3204
3383
  return /* @__PURE__ */ jsx6("div", { css: styles6.tableWrapper, children: /* @__PURE__ */ jsxs6("table", { css: styles6.table, children: [
3205
3384
  /* @__PURE__ */ jsx6("thead", { children: /* @__PURE__ */ jsxs6("tr", { children: [
@@ -3898,7 +4077,7 @@ function StudioDetailView() {
3898
4077
  ] }),
3899
4078
  /* @__PURE__ */ jsxs7("button", { css: styles7.actionBtn, onClick: handleSync, disabled: syncing, children: [
3900
4079
  /* @__PURE__ */ jsx7("svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx7("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" }) }),
3901
- syncing ? "Syncing..." : "Sync to CDN"
4080
+ syncing ? "Pushing..." : "Push to CDN"
3902
4081
  ] }),
3903
4082
  /* @__PURE__ */ jsxs7("button", { css: styles7.actionBtn, onClick: () => setShowProcessConfirm(true), children: [
3904
4083
  /* @__PURE__ */ jsx7("svg", { css: styles7.actionIcon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx7("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }),
@@ -4428,6 +4607,8 @@ var styles10 = {
4428
4607
  min-width: 0;
4429
4608
  overflow: auto;
4430
4609
  padding: 20px 24px;
4610
+ display: flex;
4611
+ flex-direction: column;
4431
4612
  `,
4432
4613
  dropOverlay: css10`
4433
4614
  position: absolute;
@@ -4467,12 +4648,19 @@ function StudioUI({ onClose, isVisible = true }) {
4467
4648
  const [meta, setMeta] = useState9(null);
4468
4649
  const [isLoading, setIsLoading] = useState9(false);
4469
4650
  const [refreshKey, setRefreshKey] = useState9(0);
4651
+ const [scanRequested, setScanRequested] = useState9(false);
4470
4652
  const [searchQuery, setSearchQuery] = useState9("");
4471
4653
  const [error, setError] = useState9(null);
4472
4654
  const [isDragging, setIsDragging] = useState9(false);
4473
4655
  const triggerRefresh = useCallback3(() => {
4474
4656
  setRefreshKey((k) => k + 1);
4475
4657
  }, []);
4658
+ const triggerScan = useCallback3(() => {
4659
+ setScanRequested(true);
4660
+ }, []);
4661
+ const clearScanRequest = useCallback3(() => {
4662
+ setScanRequested(false);
4663
+ }, []);
4476
4664
  const showError = useCallback3((title, message) => {
4477
4665
  setError({ title, message });
4478
4666
  }, []);
@@ -4574,7 +4762,7 @@ function StudioUI({ onClose, isVisible = true }) {
4574
4762
  },
4575
4763
  [onClose, focusedItem]
4576
4764
  );
4577
- useEffect3(() => {
4765
+ useEffect4(() => {
4578
4766
  if (isVisible) {
4579
4767
  document.addEventListener("keydown", handleKeyDown);
4580
4768
  document.body.style.overflow = "hidden";
@@ -4609,6 +4797,9 @@ function StudioUI({ onClose, isVisible = true }) {
4609
4797
  setIsLoading,
4610
4798
  refreshKey,
4611
4799
  triggerRefresh,
4800
+ scanRequested,
4801
+ triggerScan,
4802
+ clearScanRequest,
4612
4803
  searchQuery,
4613
4804
  setSearchQuery,
4614
4805
  error,
@@ -4695,4 +4886,4 @@ export {
4695
4886
  StudioUI,
4696
4887
  StudioUI_default as default
4697
4888
  };
4698
- //# sourceMappingURL=StudioUI-6CQ7MX7R.mjs.map
4889
+ //# sourceMappingURL=StudioUI-LWHNOTSN.mjs.map