@tulip-systems/drive 0.7.0 → 0.8.1
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/package.json +2 -2
- package/src/components/grid-card.client.tsx +4 -1
- package/src/providers/google/components/view.client.tsx +9 -1
- package/src/providers/google/lib/helpers.ts +9 -0
- package/src/providers/local/components/provider.client.tsx +2 -1
- package/src/providers/local/components/upload-zone-context.client.tsx +1 -0
- package/src/providers/local/components/upload-zone.client.tsx +14 -1
- package/src/providers/local/components/view.client.tsx +10 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tulip-systems/drive",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"license": "AGPL-3.0",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"uuid": "^13.0.0",
|
|
66
66
|
"vaul": "^1.1.2",
|
|
67
67
|
"zod": "^4.3.6",
|
|
68
|
-
"@tulip-systems/core": "0.8.
|
|
68
|
+
"@tulip-systems/core": "0.8.1"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
71
|
"@better-auth/passkey": "^1.5.5",
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
Skeleton,
|
|
18
18
|
} from "@tulip-systems/core/components";
|
|
19
19
|
import { FolderIcon } from "lucide-react";
|
|
20
|
-
import Image from "next/image";
|
|
20
|
+
import Image, { type ImageLoaderProps } from "next/image";
|
|
21
21
|
import { useRouter } from "next/navigation";
|
|
22
22
|
import type { ComponentProps } from "react";
|
|
23
23
|
import { nodeSubtypeConfig, nodeSubtypeVariants } from "@/config/types";
|
|
@@ -30,6 +30,7 @@ import { useDriveSelectionContext } from "./selection.client";
|
|
|
30
30
|
type DriveGridCardProps<TData extends DriveNode> = ComponentProps<"div"> & {
|
|
31
31
|
node: TData;
|
|
32
32
|
commands?: CommandDef<TData>[];
|
|
33
|
+
imageLoader?: (props: ImageLoaderProps) => string;
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
export function DriveGridCard<TData extends DriveNode>(props: DriveGridCardProps<TData>) {
|
|
@@ -142,6 +143,7 @@ export function DriveGridFolderCard<TData extends DriveNode>({
|
|
|
142
143
|
export function DriveGridFileCard<TData extends DriveNode>({
|
|
143
144
|
node,
|
|
144
145
|
commands,
|
|
146
|
+
imageLoader,
|
|
145
147
|
className,
|
|
146
148
|
...props
|
|
147
149
|
}: DriveGridCardProps<TData>) {
|
|
@@ -218,6 +220,7 @@ export function DriveGridFileCard<TData extends DriveNode>({
|
|
|
218
220
|
alt={node.name}
|
|
219
221
|
width={200}
|
|
220
222
|
height={200}
|
|
223
|
+
loader={imageLoader}
|
|
221
224
|
className="h-full w-full object-cover"
|
|
222
225
|
/>
|
|
223
226
|
) : (
|
|
@@ -23,6 +23,7 @@ import { DriveGridCard, DriveGridCardSkeleton } from "@/components/grid-card.cli
|
|
|
23
23
|
import { useDriveSelectionContext } from "@/components/selection.client";
|
|
24
24
|
import { useDriveViewContext } from "@/components/view.client";
|
|
25
25
|
import { googleDriveColumns } from "../config/columns-data";
|
|
26
|
+
import { googleDriveImageLoader } from "../lib/helpers";
|
|
26
27
|
import type { GoogleDriveNode } from "../lib/validators";
|
|
27
28
|
import { useGoogleDriveContext } from "./provider.client";
|
|
28
29
|
|
|
@@ -106,7 +107,14 @@ function GoogleDriveGrid(props: ComponentProps<"div">) {
|
|
|
106
107
|
return (
|
|
107
108
|
<DriveGrid {...props}>
|
|
108
109
|
{queryData.length > 0 ? (
|
|
109
|
-
queryData.map((node) =>
|
|
110
|
+
queryData.map((node) => (
|
|
111
|
+
<DriveGridCard
|
|
112
|
+
key={node.id}
|
|
113
|
+
node={node}
|
|
114
|
+
commands={commands}
|
|
115
|
+
imageLoader={googleDriveImageLoader}
|
|
116
|
+
/>
|
|
117
|
+
))
|
|
110
118
|
) : (
|
|
111
119
|
<DriveGridEmpty title="Geen resultaten gevonden" />
|
|
112
120
|
)}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Readable } from "node:stream";
|
|
2
2
|
import type { ObjectBodyInput } from "@tulip-systems/core/storage";
|
|
3
|
+
import type { ImageLoaderProps } from "next/image";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Escapes dynamic values before interpolating them into Google Drive `q` strings.
|
|
@@ -35,3 +36,11 @@ export function toGoogleDriveReadable(body: ObjectBodyInput) {
|
|
|
35
36
|
if (typeof body === "string") return Readable.from([body]);
|
|
36
37
|
return Readable.from([body]);
|
|
37
38
|
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Use Google-provided thumbnail URLs directly instead of routing them through
|
|
42
|
+
* the Next.js optimizer.
|
|
43
|
+
*/
|
|
44
|
+
export function googleDriveImageLoader({ src }: ImageLoaderProps) {
|
|
45
|
+
return src;
|
|
46
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { Allowed } from "@tulip-systems/core/auth/client";
|
|
4
|
+
import { cn } from "@tulip-systems/core/lib";
|
|
4
5
|
import { createContext, type PropsWithChildren, use } from "react";
|
|
5
6
|
import type { DriveContextValue } from "@/components/context.client";
|
|
6
7
|
import { DriveDragDropProvider, type DriveDragDropProviderProps } from "@/components/dnd.client";
|
|
@@ -71,7 +72,7 @@ export function LocalDriveProvider({
|
|
|
71
72
|
<LocalDriveContext value={{ namespace, permission, meta, readonly }}>
|
|
72
73
|
<LocalDriveUploadZone
|
|
73
74
|
disabled={isDisabled}
|
|
74
|
-
className={className}
|
|
75
|
+
className={cn("flex min-h-dvh flex-col", className)}
|
|
75
76
|
variables={{ namespace, parentId }}
|
|
76
77
|
driveUploadClient={driveUploadClient}
|
|
77
78
|
uploadHooks={uploadHooks}
|
|
@@ -13,6 +13,7 @@ export type LocalDriveUploadZoneContextValue = {
|
|
|
13
13
|
onRemove: (ids: string[]) => Promise<void>;
|
|
14
14
|
optimistic?: {
|
|
15
15
|
add?: (newValue: LocalDriveNodeWithAsset) => Promise<void> | void;
|
|
16
|
+
replace?: (input: { id: string; newValue: LocalDriveNodeWithAsset }) => Promise<void> | void;
|
|
16
17
|
remove?: (ids: string[]) => Promise<void> | void;
|
|
17
18
|
invalidate?: () => Promise<void> | void;
|
|
18
19
|
cancel?: () => Promise<void> | void;
|
|
@@ -109,7 +109,20 @@ export function LocalDriveUploadZone({
|
|
|
109
109
|
|
|
110
110
|
await optimistic?.add?.(newNode);
|
|
111
111
|
},
|
|
112
|
-
onSuccess: async (data) => {
|
|
112
|
+
onSuccess: async (data, variables) => {
|
|
113
|
+
await optimistic?.replace?.({
|
|
114
|
+
id: variables.uploadId,
|
|
115
|
+
newValue: {
|
|
116
|
+
...data,
|
|
117
|
+
asset: {
|
|
118
|
+
status: "ready",
|
|
119
|
+
name: data.name,
|
|
120
|
+
contentType: data.contentType,
|
|
121
|
+
size: data.size,
|
|
122
|
+
visibility: variables.visibility || "private",
|
|
123
|
+
} as StorageAsset,
|
|
124
|
+
},
|
|
125
|
+
});
|
|
113
126
|
await onUploadCompleted?.(data);
|
|
114
127
|
toast.success(`Succesvol geupload: ${data.name}`);
|
|
115
128
|
},
|
|
@@ -23,6 +23,7 @@ import { DriveGridCard, DriveGridCardSkeleton } from "@/components/grid-card.cli
|
|
|
23
23
|
import { useDriveSelectionContext } from "@/components/selection.client";
|
|
24
24
|
import { useDriveViewContext } from "@/components/view.client";
|
|
25
25
|
import { localDriveColumns } from "../config/columns-data";
|
|
26
|
+
import { localDriveImageLoader } from "../lib/helpers";
|
|
26
27
|
import type { LocalDriveNodeWithAsset } from "../lib/validators";
|
|
27
28
|
import { useLocalDriveContext } from "./provider.client";
|
|
28
29
|
import { useLocalDriveUploadZone } from "./upload-zone-context.client";
|
|
@@ -80,7 +81,7 @@ function LocalDriveGrid(props: ComponentProps<"div">) {
|
|
|
80
81
|
const { queryData, strategy, commands, selection, meta } =
|
|
81
82
|
useTableConfigContext<LocalDriveNodeWithAsset>();
|
|
82
83
|
const { optimistic } = useLocalDriveUploadZone();
|
|
83
|
-
|
|
84
|
+
|
|
84
85
|
const { rowCount, paginationState } = strategy;
|
|
85
86
|
const { isFetching, isFetchingNextPage, fetchNextPage } = strategy.meta as InfiniteStrategyMeta;
|
|
86
87
|
|
|
@@ -96,7 +97,14 @@ function LocalDriveGrid(props: ComponentProps<"div">) {
|
|
|
96
97
|
{queryData.length > 0 ? (
|
|
97
98
|
queryData
|
|
98
99
|
.filter((node) => !node.hidden)
|
|
99
|
-
.map((node) =>
|
|
100
|
+
.map((node) => (
|
|
101
|
+
<DriveGridCard
|
|
102
|
+
key={node.id}
|
|
103
|
+
node={node}
|
|
104
|
+
commands={commands}
|
|
105
|
+
imageLoader={localDriveImageLoader}
|
|
106
|
+
/>
|
|
107
|
+
))
|
|
100
108
|
) : (
|
|
101
109
|
<DriveGridEmpty title="Geen resultaten gevonden" />
|
|
102
110
|
)}
|