@alwith/module-drive 0.0.0-stage → 0.1.0-rc.22

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.
Files changed (107) hide show
  1. package/LICENSE +94 -0
  2. package/README.md +50 -2
  3. package/THIRD_PARTY_NOTICES.md +7 -0
  4. package/desktop-provenance.json +34 -0
  5. package/dist/badge-react.d.ts +9 -0
  6. package/dist/badge-react.js +1 -0
  7. package/dist/badge.d.ts +10 -0
  8. package/dist/badge.js +1 -0
  9. package/dist/browse.d.ts +33 -0
  10. package/dist/browse.js +1 -0
  11. package/dist/content/chat-condense.d.ts +22 -0
  12. package/dist/content/chat-condense.js +1 -0
  13. package/dist/content/collab.d.ts +34 -0
  14. package/dist/content/collab.js +1 -0
  15. package/dist/content/comment-anchors.d.ts +23 -0
  16. package/dist/content/comment-anchors.js +2 -0
  17. package/dist/content/comment-decorations.d.ts +23 -0
  18. package/dist/content/comment-decorations.js +3 -0
  19. package/dist/content/comment-drawer.d.ts +44 -0
  20. package/dist/content/comment-drawer.js +1 -0
  21. package/dist/content/comment-mentions.d.ts +18 -0
  22. package/dist/content/comment-mentions.js +1 -0
  23. package/dist/content/comment-surface.d.ts +25 -0
  24. package/dist/content/comment-surface.js +1 -0
  25. package/dist/content/condense-task.d.ts +44 -0
  26. package/dist/content/condense-task.js +1 -0
  27. package/dist/content/condense.d.ts +20 -0
  28. package/dist/content/condense.js +1 -0
  29. package/dist/content/editor.d.ts +5 -0
  30. package/dist/content/editor.js +1 -0
  31. package/dist/content/file-actions.d.ts +43 -0
  32. package/dist/content/file-actions.js +1 -0
  33. package/dist/content/file-link.d.ts +4 -0
  34. package/dist/content/file-link.js +1 -0
  35. package/dist/content/frontmatter-panel.d.ts +7 -0
  36. package/dist/content/frontmatter-panel.js +1 -0
  37. package/dist/content/frontmatter.d.ts +9 -0
  38. package/dist/content/frontmatter.js +7 -0
  39. package/dist/content/host.d.ts +49 -0
  40. package/dist/content/host.js +1 -0
  41. package/dist/content/html-bridge.d.ts +1 -0
  42. package/dist/content/html-bridge.js +187 -0
  43. package/dist/content/html-comments.d.ts +5 -0
  44. package/dist/content/html-comments.js +1 -0
  45. package/dist/content/markdown-comments.d.ts +4 -0
  46. package/dist/content/markdown-comments.js +2 -0
  47. package/dist/content/mention-picker.d.ts +10 -0
  48. package/dist/content/mention-picker.js +1 -0
  49. package/dist/content/save-version.d.ts +2 -0
  50. package/dist/content/save-version.js +1 -0
  51. package/dist/content/translations.d.ts +2 -0
  52. package/dist/content/translations.js +1 -0
  53. package/dist/content/use-file-comments.d.ts +12 -0
  54. package/dist/content/use-file-comments.js +1 -0
  55. package/dist/content/yuplink.d.ts +11 -0
  56. package/dist/content/yuplink.js +2 -0
  57. package/dist/content.css +64 -0
  58. package/dist/content.d.ts +10 -0
  59. package/dist/content.js +1 -0
  60. package/dist/contract.d.ts +780 -0
  61. package/dist/contract.js +0 -0
  62. package/dist/core.d.ts +22 -0
  63. package/dist/core.js +1 -0
  64. package/dist/files.d.ts +7 -0
  65. package/dist/files.js +1 -0
  66. package/dist/global-search.d.ts +34 -0
  67. package/dist/global-search.js +1 -0
  68. package/dist/icons.d.ts +5 -0
  69. package/dist/icons.js +1 -0
  70. package/dist/launcher.d.ts +15 -0
  71. package/dist/launcher.js +2 -0
  72. package/dist/locales.d.ts +983 -0
  73. package/dist/locales.js +1 -0
  74. package/dist/mass-delete.d.ts +9 -0
  75. package/dist/mass-delete.js +1 -0
  76. package/dist/notifications.d.ts +14 -0
  77. package/dist/notifications.js +1 -0
  78. package/dist/pinned-docs.d.ts +14 -0
  79. package/dist/pinned-docs.js +1 -0
  80. package/dist/pinned.d.ts +12 -0
  81. package/dist/pinned.js +1 -0
  82. package/dist/react.d.ts +29 -0
  83. package/dist/react.js +1 -0
  84. package/dist/roots.d.ts +10 -0
  85. package/dist/roots.js +1 -0
  86. package/dist/settings.d.ts +14 -0
  87. package/dist/settings.js +1 -0
  88. package/dist/sharing.d.ts +12 -0
  89. package/dist/sharing.js +1 -0
  90. package/dist/status.d.ts +16 -0
  91. package/dist/status.js +1 -0
  92. package/dist/styles.css +458 -0
  93. package/dist/summary.d.ts +10 -0
  94. package/dist/summary.js +1 -0
  95. package/dist/tauri.d.ts +6 -0
  96. package/dist/tauri.js +1 -0
  97. package/dist/transfer-feed.d.ts +36 -0
  98. package/dist/transfer-feed.js +1 -0
  99. package/dist/ui.d.ts +96 -0
  100. package/dist/ui.js +1 -0
  101. package/package.json +117 -4
  102. package/rust/Cargo.toml +14 -0
  103. package/rust/src/contract.rs +366 -0
  104. package/rust/src/lib.rs +5 -0
  105. package/rust/src/ownership.rs +4 -0
  106. package/rust/src/service.rs +140 -0
  107. package/rust/src/sync.rs +1602 -0
File without changes
package/dist/core.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type { DriveEvent, DriveRequest, DriveResponse, Snapshot } from "./contract.js";
2
+ export type * from "./contract.js";
3
+ export { prepareDriveFile, type DriveFileHost } from "./files.js";
4
+ export { isBrowsable } from "./browse.js";
5
+ export interface DriveTransport {
6
+ request: (request: DriveRequest) => Promise<DriveResponse>;
7
+ subscribe: (listener: (event: DriveEvent) => void) => Promise<() => void>;
8
+ }
9
+ export interface DriveState {
10
+ connected: boolean;
11
+ snapshot: Snapshot | null;
12
+ error: string | null;
13
+ }
14
+ export interface DriveController {
15
+ getSnapshot: () => DriveState;
16
+ subscribe: (listener: () => void) => () => void;
17
+ attach: () => Promise<void>;
18
+ refresh: () => Promise<void>;
19
+ request: (request: DriveRequest) => Promise<DriveResponse>;
20
+ dispose: () => void;
21
+ }
22
+ export declare function createDriveController(transport: DriveTransport): DriveController;
package/dist/core.js ADDED
@@ -0,0 +1 @@
1
+ import{prepareDriveFile as R}from"./files.js";import{isBrowsable as S}from"./browse.js";function k(c){return c instanceof Error?c.message:String(c)}function I(c){let a={connected:!1,snapshot:null,error:null},g=new Set,o=0,d=null,h=null,l=null,v=!1,u=!0,w=[],p=(e)=>{a=e;for(let n of g)n()},D=(e)=>p({...a,error:k(e)}),m=()=>{if(l!==null){v=!0;return}b.refresh().catch(D)},E=(e)=>{if(e.version!==1){o++,d?.(),d=null,h=null,l=null,w=[],u=!0,p({connected:!1,snapshot:null,error:"Incompatible Drive contract"});return}if(u||a.snapshot===null){w.push(e);return}let n=a.snapshot;if(e.generation<n.generation||e.generation===n.generation&&e.sequence<=n.sequence)return;if(e.generation!==n.generation||e.sequence!==n.sequence+1){m();return}let r={...n,sequence:e.sequence},t=e.payload;switch(t.type){case"snapshot":Object.assign(r,t.data,{sequence:e.sequence});break;case"status":if(r.status=t.data,t.data.state.kind==="idle")r.error=null;break;case"file":r.files=[...n.files.filter((s)=>s.localPath!==t.data.localPath),t.data];break;case"project":r.projects=[...n.projects.filter((s)=>String(s.projectId)!==String(t.data.projectId)),t.data];break;case"error":r.error=t.data;break;case"reconcile":m();break;case"conflict":r.error=`Conflict: ${t.data.localPath}`;break;case"readOnly":r.error=`Read-only: ${t.data.localPath}`;break;case"changed":break}p({...a,snapshot:r})},b={getSnapshot:()=>a,subscribe(e){return g.add(e),()=>{g.delete(e)}},attach(){if(a.connected)return Promise.resolve();if(h!==null)return h;let e=o,r=(async()=>{u=!0;let t=await c.subscribe((s)=>{if(e===o)E(s)});if(e!==o){t();return}d=t;try{if(await b.refresh(),e===o)p({...a,connected:!0})}catch(s){if(t(),e===o)d=null,D(s);throw s}})().finally(()=>{if(h===r)h=null});return h=r,r},refresh(){if(l!==null)return l;let e=o;u=!0;let r=(async()=>{do{v=!1,u=!0;let t=await c.request({type:"snapshot"});if(e!==o)return;if(t.type!=="snapshot"||t.data.version!==1)throw Error("Incompatible Drive contract");p({...a,snapshot:t.data,error:null}),u=!1;let s=w;w=[];for(let f of s)E(f)}while(v&&e===o)})().finally(()=>{if(l===r)l=null,u=!1});return l=r,r},async request(e){if(!a.connected)throw Error("Attach to a compatible Drive service before sending requests");let n=o,r=a.snapshot;if(!r)throw Error("Attached Drive service has no snapshot");let t=r.generation,s=["reconfigure","setPreferences","setMaxAutoDownloadMb"].includes(e.type),f=s?await c.request({type:"configuration"}):null;if(n!==o)throw Error("Drive request belongs to a disposed attachment");if(s){if(f?.type!=="configuration")throw Error("Invalid Drive configuration response");let i=await c.request({type:"snapshot"});if(n!==o)throw Error("Drive request belongs to a disposed attachment");if(i.type!=="snapshot"||i.data.version!==1)throw Error("Incompatible Drive contract");if(i.data.generation!==t)throw Error("Drive profile changed while the request was pending")}let y=await c.request(e);if(n!==o)throw Error("Drive request belongs to a disposed attachment");if(await b.refresh(),n!==o)throw Error("Drive request belongs to a disposed attachment");if(!["login","ssoLogin","resolveRootOwnership","logout","start","stop"].includes(e.type)&&t!==a.snapshot?.generation){let i=a.snapshot;if(!s||!i||f?.type!=="configuration")throw Error("Drive profile changed while the request was pending");let q=await c.request({type:"configuration"});if(n!==o)throw Error("Drive request belongs to a disposed attachment");if(q.type!=="configuration")throw Error("Invalid Drive configuration response");if(!i.configured||i.generation!==a.snapshot?.generation||r.baseUrl!==i.baseUrl||e.type!=="reconfigure"&&r.localRoot!==i.localRoot||!f.data.userId||!f.data.deviceId||f.data.userId!==q.data.userId||f.data.deviceId!==q.data.deviceId)throw Error("Drive profile changed while the request was pending");if(e.type==="reconfigure"&&(y.type!=="snapshot"||y.data.generation!==i.generation||y.data.localRoot!==i.localRoot))throw Error("Drive profile changed while the request was pending")}return y},dispose(){if(o++,d!==null)d();d=null,h=null,l=null,w=[],u=!0,p({connected:!1,snapshot:null,error:null}),g.clear()}};return b}export{I as createDriveController,S as isBrowsable,R as prepareDriveFile};
@@ -0,0 +1,7 @@
1
+ import type { DriveController } from "./core.js";
2
+ export interface DriveFileHost {
3
+ maxEditorBytes: number;
4
+ confirmDownload: (path: string, bytes: number) => Promise<boolean>;
5
+ openExternal: (path: string) => Promise<void>;
6
+ }
7
+ export declare function prepareDriveFile(controller: DriveController, path: string, host: DriveFileHost): Promise<string | null>;
package/dist/files.js ADDED
@@ -0,0 +1 @@
1
+ async function f(o,e,n){let i=o.getSnapshot().snapshot,d=e.replaceAll("\\","/"),a=i?.localRoot.replaceAll("\\","/").replace(/\/$/,""),t=e.endsWith(".yupcloud");if(!i?.configured||!a||!d.startsWith(`${a}/`)){if(t)throw Error("Start the Drive profile that owns this cloud placeholder");return e}if(!i.running)throw Error("Start Drive before opening its files");let s=await o.request({type:"file",path:e});if(s.type!=="file")throw Error("Invalid Drive file response");let r=s.data;if(!r){if(t)throw Error("This placeholder is no longer in the Drive index");return e}if(["cloudOnly","forbidden"].includes(r.state))throw Error("This file is available only in the cloud");let l=e,c=r.size??0;if(t||r.state==="notDownloaded"){if(!await n.confirmDownload(r.path,c))return null;await o.request({type:"download",projectId:r.projectId,path:r.path}),l=t?e.slice(0,-9):e}if(c>n.maxEditorBytes)return await n.openExternal(l),null;return l}export{f as prepareDriveFile};
@@ -0,0 +1,34 @@
1
+ export type DriveSearchEntry = {
2
+ name: string;
3
+ path: string;
4
+ projectName: string;
5
+ relPath: string;
6
+ isDirectory: boolean;
7
+ };
8
+ export declare const DEFAULT_LIMITS: {
9
+ maxEntries: number;
10
+ maxDepth: number;
11
+ };
12
+ export type ReadDirLike = (path: string) => Promise<Array<{
13
+ name: string;
14
+ isDirectory: boolean;
15
+ }>>;
16
+ export type DriveSearchError = {
17
+ path: string;
18
+ message: string;
19
+ };
20
+ export type SearchRoot = {
21
+ name: string;
22
+ localPath: string;
23
+ selected: boolean;
24
+ };
25
+ export declare function collectDriveEntries(roots: readonly SearchRoot[], readDir: ReadDirLike, limits?: {
26
+ maxEntries?: number;
27
+ maxDepth?: number;
28
+ }): Promise<{
29
+ entries: DriveSearchEntry[];
30
+ truncated: boolean;
31
+ errors: DriveSearchError[];
32
+ }>;
33
+ export declare function scoreEntry(entry: DriveSearchEntry, queryLower: string): number | null;
34
+ export declare function filterDriveEntries(entries: readonly DriveSearchEntry[], query: string, limit?: number): DriveSearchEntry[];
@@ -0,0 +1 @@
1
+ var d={maxEntries:20000,maxDepth:6},x=new Set([".git","node_modules",".venv","__pycache__",".DS_Store","target","dist"]);async function P(s,o,i={}){let c=i.maxEntries??d.maxEntries,h=i.maxDepth??d.maxDepth,t=[],r=[],a=!1,u=s.filter((n)=>n.selected&&n.localPath).map((n)=>({dir:n.localPath,depth:0,projectName:n.name,rootPath:n.localPath}));while(u.length>0){if(t.length>=c){a=!0;break}let n=[];for(let{dir:m,depth:p,projectName:y,rootPath:f}of u){if(t.length>=c){a=!0;break}let D;try{D=await o(m)}catch(e){r.push({path:m,message:e instanceof Error?e.message:String(e)});continue}for(let e of D){if(e.name.startsWith("."))continue;if(e.isDirectory&&x.has(e.name))continue;if(t.length>=c){a=!0;break}let l=`${m}/${e.name}`;if(t.push({name:e.name,path:l,projectName:y,relPath:l.startsWith(`${f}/`)?l.slice(f.length+1):e.name,isDirectory:e.isDirectory}),e.isDirectory&&p+1<h)n.push({dir:l,depth:p+1,projectName:y,rootPath:f})}}u=n}return{entries:t,truncated:a,errors:r}}function g(s,o){let i=s.name.toLowerCase();if(i.startsWith(o))return 0;if(i.includes(o))return 1;if(`${s.projectName}/${s.relPath}`.toLowerCase().includes(o))return 2;return null}function E(s,o,i=50){let c=o.trim().toLowerCase();if(!c)return[];let h=[];for(let t of s){let r=g(t,c);if(r!==null)h.push({entry:t,score:r})}return h.sort((t,r)=>{if(t.score!==r.score)return t.score-r.score;if(t.entry.isDirectory!==r.entry.isDirectory)return t.entry.isDirectory?1:-1;let a=t.entry.relPath.split("/").length-r.entry.relPath.split("/").length;if(a!==0)return a;return t.entry.name.localeCompare(r.entry.name)}),h.slice(0,i).map((t)=>t.entry)}export{d as DEFAULT_LIMITS,P as collectDriveEntries,E as filterDriveEntries,g as scoreEntry};
@@ -0,0 +1,5 @@
1
+ import type { ReactNode } from "react";
2
+ export type DriveIconName = "folder" | "book" | "file" | "plus" | "sparkles" | "loading" | "up" | "down" | "check";
3
+ export declare function DriveIcon({ name }: {
4
+ name: DriveIconName;
5
+ }): ReactNode;
package/dist/icons.js ADDED
@@ -0,0 +1 @@
1
+ import{jsx as a,Fragment as h,jsxs as r}from"react/jsx-runtime";var d={folder:a("path",{d:"M20 20H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5l2 2h9a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2Z"}),book:a(h,{children:a("path",{d:"M4 19.5A2.5 2.5 0 0 1 6.5 17H20M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2Z"})}),file:r(h,{children:[a("path",{d:"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"}),a("path",{d:"M14 2v6h6M8 13h8M8 17h6"})]}),plus:a("path",{d:"M12 5v14M5 12h14"}),sparkles:r(h,{children:[a("path",{d:"m12 3 2.5 6.5L21 12l-6.5 2.5L12 21l-2.5-6.5L3 12l6.5-2.5L12 3Z"}),a("path",{d:"M5 3v4M3 5h4M19 17v4M17 19h4"})]}),loading:a("path",{d:"M12 2a10 10 0 1 1-10 10"}),up:a("path",{d:"m6 9 6-6 6 6M12 3v18"}),down:a("path",{d:"m6 15 6 6 6-6M12 3v18"}),check:a("path",{d:"m20 6-11 11-5-5"})};function i({name:t}){return a("svg",{className:`alwith-drive-icon${t==="loading"?"alwith-drive-spin":""}`,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.75",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:d[t]})}export{i as DriveIcon};
@@ -0,0 +1,15 @@
1
+ import { type ReactNode } from "react";
2
+ import type { DriveController, RootInfo } from "./core.js";
3
+ import { type DriveLocale } from "./locales.js";
4
+ import { type DriveControls, type DriveHost } from "./ui.js";
5
+ export interface LauncherProps {
6
+ controller: DriveController;
7
+ controls: DriveControls;
8
+ host?: DriveHost;
9
+ locale?: DriveLocale;
10
+ currentProject?: string | null;
11
+ onOpenProject: (root: RootInfo) => Promise<void>;
12
+ confirm: (message: string) => Promise<boolean>;
13
+ onOpenSettings?: () => void;
14
+ }
15
+ export declare function DriveLauncher(props: LauncherProps): ReactNode;
@@ -0,0 +1,2 @@
1
+ import{jsx as e,jsxs as p,Fragment as G}from"react/jsx-runtime";import{useEffect as B,useMemo as H,useRef as K,useState as m}from"react";import{containerKey as Y,groupsOf as J,isBrowsable as _,rowStatusOf as X}from"./browse.js";import{collectDriveEntries as Z,filterDriveEntries as ee}from"./global-search.js";import{DriveIcon as F}from"./icons.js";import{driveTranslator as R}from"./locales.js";import{DriveNotice as V}from"./notifications.js";import{DrivePinnedDocs as ne}from"./pinned.js";import{togglePinned as te}from"./pinned-docs.js";import{DriveChoice as W,DriveMenu as A,DriveModal as re,requireHost as L,useDrive as U,useDriveAction as M}from"./ui.js";function ye(n){let{controller:s,controls:g,host:c,locale:O="en",onOpenSettings:b}=n,{Button:P}=g,{snapshot:u}=U(s),{busy:h,error:f,run:w}=M(),[S,k]=m(!1),[D,a]=m(null),[T,j]=m(null),[N,x]=m([]),[I,y]=m(null),d=R(O);B(()=>{if(x([]),a(null),y(null),!u?.running)return;let r=!0;return Promise.all([s.request({type:"ownershipGuard"}),s.request({type:"shared"})]).then(([i,v])=>{if(i.type!=="ownershipGuard"||v.type!=="shared")throw Error("Invalid Drive launcher response");if(r)a(i.data),x(v.data),y(null)}).catch((i)=>{if(r)y(String(i))}),()=>{r=!1}},[s,u?.generation,u?.running]);let o=u?.webBaseUrl?.replace(/\/+$/,""),q=async(r)=>{let i=L(c),v=u?.roots.find((E)=>String(E.projectId)===String(r.projectId)),l=async()=>{if(!o)throw Error(d("shared.notInDrive",{name:r.name}));await i.onOpenExternal(r.resourceType==="FILE"?`${o}/file/${encodeURIComponent(String(r.resourceId))}`:`${o}/shared`)};if(!v){await l();return}if(await s.request({type:"land",projectId:v.projectId}),r.localPath&&await i.pathExists(r.localPath)){await i.onOpenEntry({path:r.localPath,isDirectory:r.resourceType==="FOLDER"});return}if(r.resourceType==="FILE"){let E=await s.request({type:"localPath",fileId:r.resourceId});if(E.type!=="path")throw Error("Invalid Drive file path response");if(E.data&&await i.pathExists(E.data)){await i.onOpenEntry({path:E.data,isDirectory:!1});return}await l();return}let t=r.folderPath?`${v.localPath}/${r.folderPath}`:null;if(t&&await i.pathExists(t)){await i.onOpenEntry({path:t,isDirectory:!0});return}throw await i.onOpenEntry({path:v.localPath,isDirectory:!0}),Error(d("shared.folderMissing",{name:r.name}))};return p(G,{children:[p("header",{className:"alwith-drive-toolbar",children:[e("strong",{children:d("title")}),p("div",{className:"alwith-drive-actions",children:[e(A,{controls:g,label:d("panel.new"),items:[{label:d("newProject.title"),onSelect:()=>k(!0)},...o?[{label:d("panel.importFromFeishu"),onSelect:()=>w(()=>L(c).onOpenExternal(`${o}/admin/mirrors`))}]:[]],children:e(F,{name:"plus"})}),e(A,{controls:g,label:d("panel.more"),items:[{label:d("panel.refresh"),disabled:h,onSelect:()=>w(()=>s.request({type:"sync"}))},...o?[{label:d("panel.openWeb"),onSelect:()=>w(()=>L(c).onOpenExternal(o))},{label:d("panel.importFromFeishu"),onSelect:()=>w(()=>L(c).onOpenExternal(`${o}/admin/mirrors`))}]:[],...b?[{label:d("openSettings"),onSelect:b}]:[]]})]})]}),e(oe,{...n}),e(V,{message:f||I}),D?.active&&p("aside",{className:"alwith-drive-notice",children:[e("p",{children:d("panel.guard.notice",{count:D.unknownPersonalRoots})}),e(P,{variant:"ghost",disabled:h,onClick:()=>w(async()=>{if(await n.confirm(d("panel.guard.confirmDesc",{count:D.unknownPersonalRoots})))await s.request({type:"syncAllPersonal",enabled:!0}),a({...D,active:!1,syncAllPersonal:!0})}),children:d("panel.guard.syncAll")})]}),p("div",{className:"alwith-drive-navigation",children:[c&&e(ne,{controller:s,onOpenProject:n.onOpenProject,host:c,controls:g,locale:O,generation:u?.generation}),N.length>0&&p("details",{open:!0,className:"alwith-drive-group",children:[p("summary",{children:[d("shared.title")," ",e("span",{children:N.length})]}),N.map((r)=>{let i=`${r.resourceType}:${r.resourceId}`,v=()=>w(async()=>{j(i);try{await q(r)}finally{j(null)}});return e(A,{controls:g,context:!0,label:r.name,items:[{label:d("shared.open"),onSelect:v,disabled:h},...o?[{label:d("shared.openWeb"),onSelect:()=>w(()=>L(c).onOpenExternal(`${o}/shared`))}]:[]],children:p(P,{variant:"ghost",className:"alwith-drive-nav-open",disabled:h,title:d("shared.rowTitle",{name:r.name,project:r.projectName??"",by:r.grantedByName??""}),onClick:v,children:[e(F,{name:T===i?"loading":r.resourceType==="FOLDER"?"folder":"file"}),e("span",{children:r.name}),e("small",{children:d(`grants.level.${r.level}`)})]})},i)})]}),J(u?.roots??[]).map((r)=>e(ae,{...n,group:r},r.nodePath??r.legacy)),!(u?.roots??[]).some(_)&&e("p",{children:d("panel.empty")})]}),S&&e(se,{...n,onClose:()=>k(!1)})]})}function ae({group:n,...s}){let[g,c]=m(n.items.length<=30),[O,b]=m(g),[P,u]=m(""),h=R(s.locale),f=n.legacy==="shared",w=f?n.items.filter((a)=>a.scope==="PERSONAL"):[],S=f?n.items.filter((a)=>a.scope!=="PERSONAL"):n.items,k=S.filter((a)=>a.name.toLowerCase().includes(P.trim().toLowerCase())),{Input:D}=s.controls;return p("details",{className:"alwith-drive-group",open:g,onToggle:(a)=>{if(c(a.currentTarget.open),a.currentTarget.open)b(!0)},children:[p("summary",{children:[n.label??h(`panel.groups.${n.legacy??"shared"}`),e("span",{children:n.items.length})]}),O&&p(G,{children:[S.length>30&&e(D,{placeholder:h("panel.filter"),"aria-label":h("panel.filter"),value:P,onChange:(a)=>u(a.target.value)}),k.map((a)=>e(z,{...s,root:a},String(a.projectId))),!k.length&&!w.length&&e("p",{children:h("panel.filterEmpty")}),w.length>0&&e(le,{...s,roots:w})]})]})}function le({roots:n,...s}){let[g,c]=m(""),[O,b]=m(!1),{Input:P}=s.controls,u=R(s.locale);return p("details",{className:"alwith-drive-group",onToggle:(h)=>{if(h.currentTarget.open)b(!0)},children:[p("summary",{children:[u("panel.groups.otherPersonal"),e("span",{children:n.length})]}),O&&p(G,{children:[e(P,{"aria-label":u("panel.filter"),placeholder:u("panel.filter"),value:g,onChange:(h)=>c(h.target.value)}),n.filter((h)=>h.name.toLowerCase().includes(g.toLowerCase())).map((h)=>e(z,{...s,root:h},String(h.projectId)))]})]})}function z({root:n,controller:s,controls:g,host:c,onOpenProject:O,currentProject:b,locale:P}){let{Button:u}=g,{snapshot:h}=U(s),{busy:f,error:w,run:S}=M(),[k,D]=m(!1),a=R(P),T=h?.projects.find((y)=>String(y.projectId)===String(n.projectId)),j=k?X(T,f):null,N=()=>S(async()=>{if(D(!0),c&&await c.pathExists(n.localPath)&&(await c.readDirectory(n.localPath)).length>0){await O(n),D(!1);return}let y=await s.request({type:"land",projectId:n.projectId});if(y.type!=="root")throw Error("Drive did not return a landed project");await O(y.data),D(!1)}),x=h?.webBaseUrl?.replace(/\/+$/,""),I=[{label:a("panel.open"),onSelect:N},{label:a("condense.action"),disabled:f,onSelect:()=>S(()=>{let y=L(c);if(!y.onCondense)throw Error("Knowledge integration is unavailable");return y.onCondense(n)})},{label:a("pinned.pin"),onSelect:()=>S(()=>L(c).onPinnedDocsChange(te(L(c).pinnedDocs,{path:n.localPath,name:n.name,kind:"dir"})))},...n.cursor!==null?[{label:a("panel.reveal"),onSelect:()=>S(()=>L(c).onRevealPath(n.localPath))}]:[],...x?[{label:a("panel.openWeb"),onSelect:()=>S(()=>L(c).onOpenExternal(`${x}/project/${encodeURIComponent(n.projectKey)}`))}]:[]];return p(G,{children:[e(A,{controls:g,context:!0,label:n.name,items:I,children:p("div",{className:"alwith-drive-nav-row","data-active":b===n.localPath,children:[p(u,{variant:"ghost",className:"alwith-drive-nav-open",title:n.drivePath,"aria-label":n.name,disabled:f,onClick:N,children:[e(F,{name:f?"loading":n.kind==="KNOWLEDGE"?"book":"folder"}),e("span",{children:n.name}),e("small",{children:j?a(`panel.status.${j.kind==="syncing"&&j.total>0?"syncingProgress":j.kind}`,j.kind==="syncing"?{done:j.done,total:j.total}:j.kind==="partial"?{count:j.failed}:{}):a(`panel.containers.${Y(n)}`)})]}),e(u,{variant:"ghost",size:"icon-xs",className:"alwith-drive-condense-trigger",title:a("condense.action"),"aria-label":a("condense.action"),disabled:f,onClick:I[1].onSelect,children:e(F,{name:"sparkles"})}),e(A,{controls:g,label:`${n.name} ${a("panel.more")}`,items:I})]})}),e(V,{message:w})]})}function oe({controller:n,controls:{Input:s,Button:g},host:c,locale:O}){let{snapshot:b}=U(n),[P,u]=m(""),[h,f]=m([]),[w,S]=m(!1),{error:k,run:D}=M(),[a,T]=m(!1),[j,N]=m(null),x=K(0),I=K(!1),y=K(null),d=K(null),o=R(O),q=(b?.roots??[]).filter((l)=>l.selected).map((l)=>l.localPath).toSorted().join("\x00"),r=()=>{if(I.current||d.current?.signature===q&&Date.now()-d.current.at<60000)return;let l=++x.current,t=b?.generation,E=()=>l===x.current&&t===n.getSnapshot().snapshot?.generation;I.current=!0,T(!0),N(null),Z((b?.roots??[]).filter(_),async(C)=>{if(!E())return[];return L(c).readDirectory(C)}).then((C)=>{if(!E())return;f(C.entries),S(C.truncated),N(C.errors.length?C.errors.map((Q)=>`${Q.path}: ${Q.message}`).join(`
2
+ `):null),d.current={signature:q,at:Date.now()}}).catch((C)=>{if(E())N(C instanceof Error?C.message:String(C))}).finally(()=>{if(E())I.current=!1,T(!1)})};B(()=>{let l=(t)=>{if(t.key.toLowerCase()==="k"&&(t.metaKey||t.ctrlKey)&&!t.altKey&&!t.shiftKey)t.preventDefault(),y.current?.querySelector("input")?.focus()};return window.addEventListener("keydown",l),()=>window.removeEventListener("keydown",l)},[]),B(()=>{let l=x;return x.current++,I.current=!1,T(!1),N(null),f([]),u(""),S(!1),d.current=null,()=>{l.current++}},[n,q,b?.generation]);let i=H(()=>ee(h,P),[h,P]),v=(l)=>D(async()=>{await L(c).onOpenEntry({path:l.path,isDirectory:l.isDirectory}),u("")});return p("div",{ref:y,className:"alwith-drive-search",children:[e(s,{placeholder:`${o("search.placeholder")} ⌘K`,"aria-label":o("search.placeholder"),value:P,onFocus:r,onChange:(l)=>u(l.target.value),onKeyDown:(l)=>{if(l.key==="Escape")u("");if(l.key==="Enter"&&i[0])v(i[0])}}),e(V,{message:k||j}),P.trim()&&p("div",{className:"alwith-drive-search-results",children:[!i.length&&e("p",{children:o(a?"search.indexing":"search.empty")}),i.map((l)=>e(g,{variant:"ghost",className:"alwith-drive-search-result",onClick:()=>v(l),children:p("span",{children:[e(F,{name:l.isDirectory?"folder":"file"})," ",l.name,p("small",{children:[l.projectName," · ",l.relPath]})]})},l.path)),w&&e("p",{children:o("search.truncated")})]})]})}function se({controller:n,controls:s,onOpenProject:g,onClose:c,locale:O}){let[b,P]=m([]),[u,h]=m([]),[f,w]=m("PERSONAL"),[S,k]=m(""),[D,a]=m(""),[T,j]=m(""),[N,x]=m(null),{busy:I,error:y,run:d}=M(),o=R(O),{Button:q,Input:r}=s;B(()=>{let t=!0;return Promise.all([n.request({type:"templates"}),n.request({type:"departments"})]).then(([E,C])=>{if(E.type!=="templates"||C.type!=="departments")throw Error("Invalid project choices");if(t)P(E.data),h(C.data),k(String(E.data[0]?.id??"")),a(String(C.data[0]?.id??""))}).catch((E)=>{if(t)x(String(E))}),()=>{t=!1}},[n]);let i=b.find((t)=>String(t.id)===S),v=u.find((t)=>String(t.id)===D),l=f==="DEPT"||f==="TEAM";return e(re,{controls:s,open:!0,onOpenChange:(t)=>{if(!t&&!I)c()},title:o("newProject.title"),description:o("newProject.desc"),children:p("div",{className:"alwith-drive-form",children:[(y||N)&&e("p",{role:"alert",className:"alwith-drive-error",children:y||N}),p("label",{children:[o("newProject.name"),e(r,{autoFocus:!0,placeholder:o("newProject.namePlaceholder"),value:T,onChange:(t)=>j(t.target.value)})]}),p("label",{children:[o("newProject.scope"),e(W,{controls:s,value:f,onValueChange:(t)=>w(t),options:["PERSONAL","DEPT","TEAM","COMPANY"].map((t)=>({value:t,label:o(`newProject.scopes.${t}`)}))})]}),l&&p("label",{children:[o("newProject.department"),e(W,{controls:s,value:D,onValueChange:a,options:u.map((t)=>({value:String(t.id),label:t.name}))})]}),p("label",{children:[o("newProject.template"),e(W,{controls:s,value:S,onValueChange:k,options:b.map((t)=>({value:String(t.id),label:`${o(`panel.containers.${t.kind==="KNOWLEDGE"?"knowledge":"material"}`)} · ${t.name}${t.description?` · ${t.description}`:""}`}))})]}),i&&e("p",{children:o("newProject.preview",{node:l?v?.name??o(`newProject.scopes.${f}`):o(`newProject.scopes.${f}`),container:o(`panel.containers.${i.kind==="KNOWLEDGE"?"knowledge":"material"}`)})}),p("div",{className:"alwith-drive-actions",children:[e(q,{variant:"outline",disabled:I,onClick:c,children:o("newProject.cancel")}),e(q,{disabled:I||!T.trim()||!i||l&&!v,onClick:()=>d(async()=>{if(!i)throw Error("Select a template");let t=await n.request({type:"createProject",request:{templateId:i.id,name:T.trim(),scope:f,departmentId:l?v?.id:null,topicId:null}});if(t.type!=="root")throw Error("Created project is unavailable");await g(t.data),c()}),children:o(I?"newProject.creating":"newProject.create")})]})]})})}export{ye as DriveLauncher};