@tulip-systems/drive-local 0.11.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.
Files changed (61) hide show
  1. package/LICENSE +662 -0
  2. package/dist/client.d.mts +12 -0
  3. package/dist/client.mjs +12 -0
  4. package/dist/database/drizzle/lib/adapter.d.mts +310 -0
  5. package/dist/database/drizzle/lib/adapter.mjs +520 -0
  6. package/dist/database/drizzle/lib/compilers.d.mts +395 -0
  7. package/dist/database/drizzle/lib/compilers.mjs +21 -0
  8. package/dist/database/drizzle/lib/schema.d.mts +61 -0
  9. package/dist/drizzle.d.mts +4 -0
  10. package/dist/drizzle.mjs +3 -0
  11. package/dist/index.d.mts +8 -0
  12. package/dist/index.mjs +8 -0
  13. package/dist/root/components/command-file-update.d.mts +11 -0
  14. package/dist/root/components/command-file-update.mjs +44 -0
  15. package/dist/root/components/command-file-upload.d.mts +5 -0
  16. package/dist/root/components/command-file-upload.mjs +31 -0
  17. package/dist/root/components/command-folder-create.d.mts +11 -0
  18. package/dist/root/components/command-folder-create.mjs +50 -0
  19. package/dist/root/components/command-folder-update.d.mts +11 -0
  20. package/dist/root/components/command-folder-update.mjs +44 -0
  21. package/dist/root/components/content.client.d.mts +5 -0
  22. package/dist/root/components/content.client.mjs +5 -0
  23. package/dist/root/components/navigation.client.d.mts +11 -0
  24. package/dist/root/components/navigation.client.mjs +12 -0
  25. package/dist/root/components/provider.client.d.mts +16 -0
  26. package/dist/root/components/provider.client.mjs +65 -0
  27. package/dist/root/components/upload-zone-context.client.d.mts +36 -0
  28. package/dist/root/components/upload-zone-context.client.mjs +19 -0
  29. package/dist/root/components/upload-zone.client.d.mts +16 -0
  30. package/dist/root/components/upload-zone.client.mjs +147 -0
  31. package/dist/root/components/view.client.d.mts +20 -0
  32. package/dist/root/components/view.client.mjs +86 -0
  33. package/dist/root/config/columns-data.d.mts +6 -0
  34. package/dist/root/config/columns-data.mjs +62 -0
  35. package/dist/root/config/filters.d.mts +404 -0
  36. package/dist/root/config/filters.mjs +122 -0
  37. package/dist/root/config/sorting.d.mts +38 -0
  38. package/dist/root/config/sorting.mjs +26 -0
  39. package/dist/root/lib/constants.d.mts +12 -0
  40. package/dist/root/lib/constants.mjs +27 -0
  41. package/dist/root/lib/database/contracts.d.mts +112 -0
  42. package/dist/root/lib/database/filters.d.mts +28 -0
  43. package/dist/root/lib/database/filters.mjs +73 -0
  44. package/dist/root/lib/helpers.d.mts +33 -0
  45. package/dist/root/lib/helpers.mjs +78 -0
  46. package/dist/root/lib/route-handler.server.d.mts +36 -0
  47. package/dist/root/lib/route-handler.server.mjs +111 -0
  48. package/dist/root/lib/router.server.d.mts +819 -0
  49. package/dist/root/lib/router.server.mjs +87 -0
  50. package/dist/root/lib/search-params.d.mts +15 -0
  51. package/dist/root/lib/search-params.mjs +6 -0
  52. package/dist/root/lib/service.server.d.mts +522 -0
  53. package/dist/root/lib/service.server.mjs +613 -0
  54. package/dist/root/lib/upload.client.d.mts +60 -0
  55. package/dist/root/lib/upload.client.mjs +97 -0
  56. package/dist/root/lib/validators.d.mts +710 -0
  57. package/dist/root/lib/validators.mjs +116 -0
  58. package/dist/server.d.mts +5 -0
  59. package/dist/server.mjs +4 -0
  60. package/package.json +83 -0
  61. package/styles.css +1 -0
@@ -0,0 +1,50 @@
1
+ "use client";
2
+ import { createLocalDriveFolderInputSchema } from "../lib/validators.mjs";
3
+ import { useDriveNavigation } from "@tulip-systems/drive/client";
4
+ import { FolderPlus } from "lucide-react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { standardSchemaResolver } from "@hookform/resolvers/standard-schema";
7
+ import { CommandFormDialog, CommandFormDialogCancel, CommandFormDialogContent, CommandFormDialogFields, CommandFormDialogFooter, CommandFormDialogHeader, CommandFormDialogSubmit, CommandFormDialogTitle, CommandFormDialogTrigger, CommandLabel } from "@tulip-systems/commands/client";
8
+ import { Input } from "@tulip-systems/ui/input";
9
+ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@tulip-systems/ui/react-hook-form";
10
+ import { useForm } from "react-hook-form";
11
+ //#region src/root/components/command-folder-create.tsx
12
+ function LocalDriveFoldersCreateCommand({ defaultValues, variables, mutation }) {
13
+ const { parentId } = useDriveNavigation();
14
+ const form = useForm({
15
+ resolver: standardSchemaResolver(createLocalDriveFolderInputSchema),
16
+ defaultValues: {
17
+ ...defaultValues,
18
+ parentId
19
+ }
20
+ });
21
+ return /* @__PURE__ */ jsx(Form, {
22
+ ...form,
23
+ children: /* @__PURE__ */ jsxs(CommandFormDialog, { children: [/* @__PURE__ */ jsxs(CommandFormDialogTrigger, {
24
+ label: "Folder toevoegen",
25
+ hotkey: "mod+i",
26
+ children: [/* @__PURE__ */ jsx(FolderPlus, { className: "size-4" }), /* @__PURE__ */ jsx(CommandLabel, {})]
27
+ }), /* @__PURE__ */ jsxs(CommandFormDialogContent, {
28
+ variables,
29
+ mutation,
30
+ children: [
31
+ /* @__PURE__ */ jsx(CommandFormDialogHeader, { children: /* @__PURE__ */ jsx(CommandFormDialogTitle, { children: "Folder toevoegen" }) }),
32
+ /* @__PURE__ */ jsx(CommandFormDialogFields, { children: /* @__PURE__ */ jsx(FormField, {
33
+ control: form.control,
34
+ name: "name",
35
+ render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
36
+ /* @__PURE__ */ jsx(FormLabel, { children: "Naam" }),
37
+ /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(Input, {
38
+ ...field,
39
+ value: field.value ?? ""
40
+ }) }),
41
+ /* @__PURE__ */ jsx(FormMessage, {})
42
+ ] })
43
+ }) }),
44
+ /* @__PURE__ */ jsxs(CommandFormDialogFooter, { children: [/* @__PURE__ */ jsx(CommandFormDialogCancel, { children: "Annuleren" }), /* @__PURE__ */ jsx(CommandFormDialogSubmit, { children: "Toevoegen" })] })
45
+ ]
46
+ })] })
47
+ });
48
+ }
49
+ //#endregion
50
+ export { LocalDriveFoldersCreateCommand };
@@ -0,0 +1,11 @@
1
+ import { UpdateLocalDriveNodeInput } from "../lib/validators.mjs";
2
+ import { DefaultError, MutationOptions } from "@tanstack/react-query";
3
+ //#region src/root/components/command-folder-update.d.ts
4
+ type LocalDriveFoldersUpdateCommandProps<TData = unknown, TError = DefaultError, TVariables = unknown, TOnMutateResult = unknown> = {
5
+ defaultValues: Partial<UpdateLocalDriveNodeInput>;
6
+ variables: (values: UpdateLocalDriveNodeInput) => TVariables;
7
+ mutation: MutationOptions<TData, TError, TVariables, TOnMutateResult>;
8
+ };
9
+ declare function LocalDriveFoldersUpdateCommand<TData = unknown, TError = DefaultError, TVariables = unknown, TOnMutateResult = unknown>({ defaultValues, variables, mutation }: LocalDriveFoldersUpdateCommandProps<TData, TError, TVariables, TOnMutateResult>): import("react").JSX.Element;
10
+ //#endregion
11
+ export { LocalDriveFoldersUpdateCommand, LocalDriveFoldersUpdateCommandProps };
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ import { updateLocalDriveNodeInputSchema } from "../lib/validators.mjs";
3
+ import { FolderPen } from "lucide-react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { standardSchemaResolver } from "@hookform/resolvers/standard-schema";
6
+ import { CommandFormDialog, CommandFormDialogCancel, CommandFormDialogContent, CommandFormDialogFields, CommandFormDialogFooter, CommandFormDialogHeader, CommandFormDialogSubmit, CommandFormDialogTitle, CommandFormDialogTrigger, CommandLabel } from "@tulip-systems/commands/client";
7
+ import { Input } from "@tulip-systems/ui/input";
8
+ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@tulip-systems/ui/react-hook-form";
9
+ import { useForm } from "react-hook-form";
10
+ //#region src/root/components/command-folder-update.tsx
11
+ function LocalDriveFoldersUpdateCommand({ defaultValues, variables, mutation }) {
12
+ const form = useForm({
13
+ resolver: standardSchemaResolver(updateLocalDriveNodeInputSchema),
14
+ defaultValues
15
+ });
16
+ return /* @__PURE__ */ jsx(Form, {
17
+ ...form,
18
+ children: /* @__PURE__ */ jsxs(CommandFormDialog, { children: [/* @__PURE__ */ jsxs(CommandFormDialogTrigger, {
19
+ label: "Wijzigen",
20
+ children: [/* @__PURE__ */ jsx(FolderPen, { className: "size-4" }), /* @__PURE__ */ jsx(CommandLabel, {})]
21
+ }), /* @__PURE__ */ jsxs(CommandFormDialogContent, {
22
+ variables,
23
+ mutation,
24
+ children: [
25
+ /* @__PURE__ */ jsx(CommandFormDialogHeader, { children: /* @__PURE__ */ jsx(CommandFormDialogTitle, { children: "Folder wijzigen" }) }),
26
+ /* @__PURE__ */ jsx(CommandFormDialogFields, { children: /* @__PURE__ */ jsx(FormField, {
27
+ control: form.control,
28
+ name: "name",
29
+ render: ({ field }) => /* @__PURE__ */ jsxs(FormItem, { children: [
30
+ /* @__PURE__ */ jsx(FormLabel, { children: "Naam" }),
31
+ /* @__PURE__ */ jsx(FormControl, { children: /* @__PURE__ */ jsx(Input, {
32
+ ...field,
33
+ value: field.value ?? ""
34
+ }) }),
35
+ /* @__PURE__ */ jsx(FormMessage, {})
36
+ ] })
37
+ }) }),
38
+ /* @__PURE__ */ jsxs(CommandFormDialogFooter, { children: [/* @__PURE__ */ jsx(CommandFormDialogCancel, { children: "Annuleren" }), /* @__PURE__ */ jsx(CommandFormDialogSubmit, { children: "Opslaan" })] })
39
+ ]
40
+ })] })
41
+ });
42
+ }
43
+ //#endregion
44
+ export { LocalDriveFoldersUpdateCommand };
@@ -0,0 +1,5 @@
1
+ import { DriveContent } from "@tulip-systems/drive/client";
2
+ //#region src/root/components/content.client.d.ts
3
+ declare const LocalDriveContent: typeof DriveContent;
4
+ //#endregion
5
+ export { LocalDriveContent };
@@ -0,0 +1,5 @@
1
+ import { DriveContent } from "@tulip-systems/drive/client";
2
+ //#region src/root/components/content.client.tsx
3
+ const LocalDriveContent = DriveContent;
4
+ //#endregion
5
+ export { LocalDriveContent };
@@ -0,0 +1,11 @@
1
+ import { DriveBreadcrumb, DriveHeader, DriveHeaderBreadcrumbs, DriveHeaderTools, DriveToolbar, DriveToolbarTools, DriveViewSwitcher } from "@tulip-systems/drive/client";
2
+ //#region src/root/components/navigation.client.d.ts
3
+ declare const LocalDriveHeader: typeof DriveHeader;
4
+ declare const LocalDriveHeaderBreadcrumbs: typeof DriveHeaderBreadcrumbs;
5
+ declare const LocalDriveHeaderTools: typeof DriveHeaderTools;
6
+ declare const LocalDriveToolbar: typeof DriveToolbar;
7
+ declare const LocalDriveToolbarBreadcrumbs: typeof import("@tulip-systems/drive/client").DriveBreadcrumbs;
8
+ declare const LocalDriveToolbarTools: typeof DriveToolbarTools;
9
+ declare const LocalDriveViewSwitcher: typeof DriveViewSwitcher;
10
+ //#endregion
11
+ export { type DriveBreadcrumb, LocalDriveHeader, LocalDriveHeaderBreadcrumbs, LocalDriveHeaderTools, LocalDriveToolbar, LocalDriveToolbarBreadcrumbs, LocalDriveToolbarTools, LocalDriveViewSwitcher };
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { DriveHeader, DriveHeaderBreadcrumbs, DriveHeaderTools, DriveToolbar, DriveToolbarBreadcrumbs, DriveToolbarTools, DriveViewSwitcher } from "@tulip-systems/drive/client";
3
+ //#region src/root/components/navigation.client.tsx
4
+ const LocalDriveHeader = DriveHeader;
5
+ const LocalDriveHeaderBreadcrumbs = DriveHeaderBreadcrumbs;
6
+ const LocalDriveHeaderTools = DriveHeaderTools;
7
+ const LocalDriveToolbar = DriveToolbar;
8
+ const LocalDriveToolbarBreadcrumbs = DriveToolbarBreadcrumbs;
9
+ const LocalDriveToolbarTools = DriveToolbarTools;
10
+ const LocalDriveViewSwitcher = DriveViewSwitcher;
11
+ //#endregion
12
+ export { LocalDriveHeader, LocalDriveHeaderBreadcrumbs, LocalDriveHeaderTools, LocalDriveToolbar, LocalDriveToolbarBreadcrumbs, LocalDriveToolbarTools, LocalDriveViewSwitcher };
@@ -0,0 +1,16 @@
1
+ import { LocalDriveUploadZoneProps } from "./upload-zone.client.mjs";
2
+ import { DriveContextValue, DriveDragDropProviderProps, DriveNavigationConfig, DriveSelectionContextValue, DriveViewProviderProps } from "@tulip-systems/drive/client";
3
+ import { PropsWithChildren } from "react";
4
+ //#region src/root/components/provider.client.d.ts
5
+ type LocalDriveContextValue = DriveContextValue & {
6
+ readonly?: boolean;
7
+ };
8
+ declare const LocalDriveContext: import("react").Context<LocalDriveContextValue>;
9
+ declare function useLocalDriveContext(): LocalDriveContextValue;
10
+ type LocalDriveProviderProps = PropsWithChildren<LocalDriveContextValue & Partial<DriveSelectionContextValue> & Pick<DriveViewProviderProps, "defaultView"> & Pick<DriveDragDropProviderProps, "onMove"> & Pick<LocalDriveUploadZoneProps, "driveUploadClient" | "uploadHooks" | "onUploadCompleted" | "onUploadFailed" | "optimistic" | "disabled" | "className"> & {
11
+ parentId: string | null;
12
+ navigation: DriveNavigationConfig;
13
+ }>;
14
+ declare function LocalDriveProvider({ defaultView, namespace, parentId, permission, meta, readonly, selection, selectionConditions, onMove, driveUploadClient, uploadHooks, onUploadCompleted, onUploadFailed, optimistic, disabled, className, navigation, children }: LocalDriveProviderProps): import("react").JSX.Element;
15
+ //#endregion
16
+ export { LocalDriveContext, LocalDriveContextValue, LocalDriveProvider, LocalDriveProviderProps, useLocalDriveContext };
@@ -0,0 +1,65 @@
1
+ "use client";
2
+ import { LocalDriveUploadZone } from "./upload-zone.client.mjs";
3
+ import { DriveDragDropProvider, DriveNavigationProvider, DriveSelectionProvider, DriveViewProvider } from "@tulip-systems/drive/client";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { cn } from "@tulip-systems/ui/cn";
6
+ import { createContext, use, useMemo } from "react";
7
+ import { Allowed } from "@tulip-systems/auth/permissions/client";
8
+ //#region src/root/components/provider.client.tsx
9
+ const LocalDriveContext = createContext({});
10
+ function useLocalDriveContext() {
11
+ const context = use(LocalDriveContext);
12
+ if (!context) throw new Error("LocalDriveContext not found!");
13
+ return context;
14
+ }
15
+ function LocalDriveProvider({ defaultView, namespace, parentId, permission, meta, readonly = false, selection, selectionConditions, onMove, driveUploadClient, uploadHooks, onUploadCompleted, onUploadFailed, optimistic, disabled, className, navigation, children }) {
16
+ const isDisabled = disabled ?? readonly;
17
+ const context = useMemo(() => ({
18
+ namespace,
19
+ permission,
20
+ meta,
21
+ readonly
22
+ }), [
23
+ namespace,
24
+ permission,
25
+ meta,
26
+ readonly
27
+ ]);
28
+ return /* @__PURE__ */ jsx(DriveNavigationProvider, {
29
+ parentId,
30
+ navigation,
31
+ children: /* @__PURE__ */ jsx(Allowed, {
32
+ permission,
33
+ children: /* @__PURE__ */ jsx(DriveSelectionProvider, {
34
+ selection,
35
+ selectionConditions,
36
+ children: /* @__PURE__ */ jsx(DriveViewProvider, {
37
+ defaultView,
38
+ children: /* @__PURE__ */ jsx(DriveDragDropProvider, {
39
+ disabled: isDisabled,
40
+ onMove,
41
+ children: /* @__PURE__ */ jsx(LocalDriveContext, {
42
+ value: context,
43
+ children: /* @__PURE__ */ jsx(LocalDriveUploadZone, {
44
+ disabled: isDisabled,
45
+ className: cn("flex min-h-dvh flex-col", className),
46
+ variables: {
47
+ namespace,
48
+ parentId
49
+ },
50
+ driveUploadClient,
51
+ uploadHooks,
52
+ onUploadCompleted,
53
+ onUploadFailed,
54
+ optimistic,
55
+ children
56
+ })
57
+ })
58
+ })
59
+ })
60
+ })
61
+ })
62
+ });
63
+ }
64
+ //#endregion
65
+ export { LocalDriveContext, LocalDriveProvider, useLocalDriveContext };
@@ -0,0 +1,36 @@
1
+ import { LocalDriveFileNode, LocalDriveNodeWithAsset } from "../lib/validators.mjs";
2
+ import { LocalDriveUploadClient } from "../lib/upload.client.mjs";
3
+ import React from "react";
4
+ //#region src/root/components/upload-zone-context.client.d.ts
5
+ /**
6
+ * Upload Zone Context Value
7
+ */
8
+ type LocalDriveUploadZoneContextValue = {
9
+ driveUploadClient: LocalDriveUploadClient;
10
+ onUpload: (file: File) => Promise<LocalDriveFileNode>;
11
+ onRemove: (ids: string[]) => Promise<void>;
12
+ optimistic?: {
13
+ add?: (newValue: LocalDriveNodeWithAsset) => Promise<void> | void;
14
+ replace?: (input: {
15
+ id: string;
16
+ newValue: LocalDriveNodeWithAsset;
17
+ }) => Promise<void> | void;
18
+ remove?: (ids: string[]) => Promise<void> | void;
19
+ invalidate?: () => Promise<void> | void;
20
+ cancel?: () => Promise<void> | void;
21
+ };
22
+ disabled?: boolean;
23
+ };
24
+ /**
25
+ * Upload Zone Context
26
+ */
27
+ declare const LocalDriveUploadZoneContext: React.Context<LocalDriveUploadZoneContextValue | null>;
28
+ type DriveUploadZoneContextValue = LocalDriveUploadZoneContextValue;
29
+ declare const DriveUploadZoneContext: React.Context<LocalDriveUploadZoneContextValue | null>;
30
+ /**
31
+ * Upload Zone Hook
32
+ */
33
+ declare function useLocalDriveUploadZone(): LocalDriveUploadZoneContextValue;
34
+ declare const useDriveUploadZone: typeof useLocalDriveUploadZone;
35
+ //#endregion
36
+ export { DriveUploadZoneContext, DriveUploadZoneContextValue, LocalDriveUploadZoneContext, LocalDriveUploadZoneContextValue, useDriveUploadZone, useLocalDriveUploadZone };
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import React from "react";
3
+ //#region src/root/components/upload-zone-context.client.tsx
4
+ /**
5
+ * Upload Zone Context
6
+ */
7
+ const LocalDriveUploadZoneContext = React.createContext(null);
8
+ const DriveUploadZoneContext = LocalDriveUploadZoneContext;
9
+ /**
10
+ * Upload Zone Hook
11
+ */
12
+ function useLocalDriveUploadZone() {
13
+ const context = React.useContext(LocalDriveUploadZoneContext);
14
+ if (!context) throw new Error("useUploadZone must be used within an UploadZoneContext provider");
15
+ return context;
16
+ }
17
+ const useDriveUploadZone = useLocalDriveUploadZone;
18
+ //#endregion
19
+ export { DriveUploadZoneContext, LocalDriveUploadZoneContext, useDriveUploadZone, useLocalDriveUploadZone };
@@ -0,0 +1,16 @@
1
+ import { LocalDriveFileNode } from "../lib/validators.mjs";
2
+ import { LocalDriveUploadHooks, PrepareLocalDriveUploadInput } from "../lib/upload.client.mjs";
3
+ import { LocalDriveUploadZoneContextValue } from "./upload-zone-context.client.mjs";
4
+ import { ComponentProps } from "react";
5
+ //#region src/root/components/upload-zone.client.d.ts
6
+ type LocalDriveUploadZoneProps = ComponentProps<"div"> & Pick<LocalDriveUploadZoneContextValue, "optimistic" | "driveUploadClient" | "disabled"> & {
7
+ variables: Pick<PrepareLocalDriveUploadInput, "namespace" | "parentId" | "readonly" | "hidden" | "visibility">;
8
+ uploadHooks?: LocalDriveUploadHooks;
9
+ onUploadCompleted?: (node: LocalDriveFileNode) => Promise<void> | void;
10
+ onUploadFailed?: (error: unknown) => Promise<void> | void;
11
+ };
12
+ type DriveUploadZoneProps = LocalDriveUploadZoneProps;
13
+ declare function LocalDriveUploadZone({ variables, optimistic, driveUploadClient, uploadHooks, onUploadCompleted, onUploadFailed, disabled, children, className, ...props }: LocalDriveUploadZoneProps): import("react").JSX.Element;
14
+ declare const DriveUploadZone: typeof LocalDriveUploadZone;
15
+ //#endregion
16
+ export { DriveUploadZone, DriveUploadZoneProps, LocalDriveUploadZone, LocalDriveUploadZoneProps };
@@ -0,0 +1,147 @@
1
+ "use client";
2
+ import { inferLocalDriveNodeSubtype } from "../lib/helpers.mjs";
3
+ import { LocalDriveUploadZoneContext } from "./upload-zone-context.client.mjs";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { cn } from "@tulip-systems/ui/cn";
6
+ import { useCallback } from "react";
7
+ import { useAction } from "@tulip-systems/core/client";
8
+ import { toast } from "@tulip-systems/ui/sonner";
9
+ import { useDropzone } from "react-dropzone";
10
+ //#region src/root/components/upload-zone.client.tsx
11
+ function LocalDriveUploadZone({ variables, optimistic, driveUploadClient, uploadHooks, onUploadCompleted, onUploadFailed, disabled = false, children, className, ...props }) {
12
+ /**
13
+ * Delete mutation
14
+ */
15
+ const deleteMutation = useAction({
16
+ mutationFn: async (ids) => driveUploadClient.deleteFiles(ids),
17
+ onMutate: async (ids) => {
18
+ await optimistic?.cancel?.();
19
+ await optimistic?.remove?.(ids);
20
+ },
21
+ onError: async (error) => {
22
+ console.error("Delete failed upload error: ", error);
23
+ await onUploadFailed?.(error);
24
+ },
25
+ onSettled: () => {
26
+ optimistic?.invalidate?.();
27
+ }
28
+ });
29
+ /**
30
+ * Upload mutation
31
+ */
32
+ const uploadMutation = useAction({
33
+ mutationFn: async (params) => driveUploadClient.upload(params, uploadHooks),
34
+ onMutate: async (variables) => {
35
+ await optimistic?.cancel?.();
36
+ const newNode = {
37
+ id: variables.uploadId,
38
+ provider: "local",
39
+ createdAt: /* @__PURE__ */ new Date(),
40
+ updatedAt: /* @__PURE__ */ new Date(),
41
+ type: "file",
42
+ name: variables.file.name,
43
+ namespace: variables.namespace,
44
+ parentId: variables.parentId ?? null,
45
+ size: variables.file.size,
46
+ contentType: variables.file.type || "application/octet-stream",
47
+ readonly: variables.readonly ?? false,
48
+ hidden: variables.hidden ?? false,
49
+ archivedAt: null,
50
+ assetId: null,
51
+ subtype: inferLocalDriveNodeSubtype({
52
+ name: variables.file.name,
53
+ contentType: variables.file.type || "application/octet-stream"
54
+ }),
55
+ links: {
56
+ view: null,
57
+ download: null,
58
+ preview: null,
59
+ thumbnail: null
60
+ },
61
+ availability: "pending",
62
+ asset: {
63
+ status: "pending",
64
+ name: variables.file.name,
65
+ contentType: variables.file.type || "application/octet-stream",
66
+ size: variables.file.size,
67
+ visibility: variables.visibility || "private"
68
+ }
69
+ };
70
+ await optimistic?.add?.(newNode);
71
+ },
72
+ onSuccess: async (data, variables) => {
73
+ await optimistic?.replace?.({
74
+ id: variables.uploadId ?? "",
75
+ newValue: {
76
+ ...data,
77
+ asset: {
78
+ status: "ready",
79
+ name: data.name,
80
+ contentType: data.contentType,
81
+ size: data.size,
82
+ visibility: variables.visibility || "private"
83
+ }
84
+ }
85
+ });
86
+ await onUploadCompleted?.(data);
87
+ toast.success(`Succesvol geupload: ${data.name}`);
88
+ },
89
+ onError: async (error) => {
90
+ await onUploadFailed?.(error);
91
+ console.error("Upload error: ", error);
92
+ toast.error("Bestand uploaden mislukt", { description: error instanceof Error ? error.message : void 0 });
93
+ },
94
+ onSettled: () => {
95
+ optimistic?.invalidate?.();
96
+ }
97
+ });
98
+ /**
99
+ * Upload file handler
100
+ */
101
+ const onUpload = useCallback(async (file) => {
102
+ console.info("Uploading file", file);
103
+ const req = driveUploadClient.prepareUpload({
104
+ ...variables,
105
+ file
106
+ });
107
+ return await uploadMutation.mutateAsync(req);
108
+ }, [
109
+ driveUploadClient,
110
+ variables,
111
+ uploadMutation
112
+ ]);
113
+ /**
114
+ * Drop handler
115
+ */
116
+ const onDrop = useCallback(async (acceptedFiles) => {
117
+ if (acceptedFiles.length === 0) return;
118
+ await Promise.allSettled(acceptedFiles.map(onUpload));
119
+ }, [onUpload]);
120
+ const { getRootProps, getInputProps, isDragActive } = useDropzone({
121
+ onDrop,
122
+ noClick: true,
123
+ disabled
124
+ });
125
+ return /* @__PURE__ */ jsxs("div", {
126
+ ...props,
127
+ ...getRootProps(),
128
+ className: cn("relative z-0", className),
129
+ children: [
130
+ /* @__PURE__ */ jsx("input", { ...getInputProps() }),
131
+ isDragActive && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-10 rounded-md bg-primary/20 opacity-70 backdrop-blur-3xl" }),
132
+ /* @__PURE__ */ jsx(LocalDriveUploadZoneContext, {
133
+ value: {
134
+ driveUploadClient,
135
+ onUpload,
136
+ onRemove: deleteMutation.mutateAsync,
137
+ optimistic,
138
+ disabled
139
+ },
140
+ children
141
+ })
142
+ ]
143
+ });
144
+ }
145
+ const DriveUploadZone = LocalDriveUploadZone;
146
+ //#endregion
147
+ export { DriveUploadZone, LocalDriveUploadZone };
@@ -0,0 +1,20 @@
1
+ import { LocalDriveNodeWithAsset } from "../lib/validators.mjs";
2
+ import { TableColumnDef } from "@tulip-systems/data-tables";
3
+ import { useInfiniteStrategy } from "@tulip-systems/data-tables/client";
4
+ import { DriveViewCommands, createDriveViewConfig } from "@tulip-systems/drive/client";
5
+ import { ComponentProps } from "react";
6
+ import { VisibilityState } from "@tanstack/react-table";
7
+ //#region src/root/components/view.client.d.ts
8
+ type LocalDriveViewProviderProps<TData extends LocalDriveNodeWithAsset = LocalDriveNodeWithAsset> = ComponentProps<"div"> & {
9
+ queryData: TData[];
10
+ columns?: TableColumnDef<TData>[];
11
+ strategy: ReturnType<typeof useInfiniteStrategy>;
12
+ commands?: DriveViewCommands<TData>;
13
+ columnVisibility?: VisibilityState;
14
+ sorting?: Parameters<typeof createDriveViewConfig<TData>>[0]["sorting"];
15
+ };
16
+ declare function LocalDriveViewProvider<TData extends LocalDriveNodeWithAsset = LocalDriveNodeWithAsset>({ queryData, columns, strategy, commands, columnVisibility, sorting, children, ...props }: LocalDriveViewProviderProps<TData>): import("react").JSX.Element;
17
+ declare function LocalDriveView(): import("react").JSX.Element | null;
18
+ declare function LocalDriveViewLoading({ ...props }: ComponentProps<"div">): import("react").JSX.Element;
19
+ //#endregion
20
+ export { LocalDriveView, LocalDriveViewLoading, LocalDriveViewProvider };
@@ -0,0 +1,86 @@
1
+ "use client";
2
+ import { localDriveColumns } from "../config/columns-data.mjs";
3
+ import { localDriveImageLoader } from "../lib/helpers.mjs";
4
+ import { useLocalDriveUploadZone } from "./upload-zone-context.client.mjs";
5
+ import { useLocalDriveContext } from "./provider.client.mjs";
6
+ import { TableLayout, TableSkeleton } from "@tulip-systems/data-tables";
7
+ import { DataTable } from "@tulip-systems/data-tables/client";
8
+ import { DriveGrid, DriveGridBottombar, DriveGridCard, DriveGridCardSkeleton, DriveGridEmpty, DriveGridLoading, DriveViewConfigProvider, createDriveViewConfig, useDriveSelectionContext, useDriveViewConfig, useDriveViewContext } from "@tulip-systems/drive/client";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ import { FloatingCommandMenu } from "@tulip-systems/commands/client";
11
+ import { useMemo } from "react";
12
+ //#region src/root/components/view.client.tsx
13
+ function LocalDriveViewProvider({ queryData, columns = localDriveColumns, strategy, commands, columnVisibility, sorting, children, ...props }) {
14
+ const { meta } = useLocalDriveContext();
15
+ const selectionContext = useDriveSelectionContext();
16
+ const config = createDriveViewConfig({
17
+ queryData,
18
+ columns,
19
+ strategy,
20
+ commands,
21
+ meta,
22
+ columnVisibility,
23
+ selection: selectionContext?.selection,
24
+ sorting
25
+ });
26
+ return /* @__PURE__ */ jsx(DriveViewConfigProvider, {
27
+ config,
28
+ children: /* @__PURE__ */ jsx(TableLayout, {
29
+ ...props,
30
+ children
31
+ })
32
+ });
33
+ }
34
+ function LocalDriveView() {
35
+ const { view } = useDriveViewContext();
36
+ if (view === "grid") return /* @__PURE__ */ jsx(LocalDriveGrid, {});
37
+ if (view === "list") return /* @__PURE__ */ jsx(LocalDriveList, {});
38
+ return null;
39
+ }
40
+ function LocalDriveGrid(props) {
41
+ const { queryData, strategy, commands, selection, meta } = useDriveViewConfig();
42
+ const { optimistic } = useLocalDriveUploadZone();
43
+ const { rowCount, paginationState } = strategy;
44
+ const { isFetching, isFetchingNextPage, fetchNextPage } = strategy.meta;
45
+ const hasNextPage = rowCount == null ? false : queryData.length < rowCount;
46
+ const selectedData = useMemo(() => queryData.filter((node) => selection?.rowSelection?.[node.id] === true), [queryData, selection?.rowSelection]);
47
+ return /* @__PURE__ */ jsxs(DriveGrid, {
48
+ ...props,
49
+ children: [
50
+ queryData.length > 0 ? queryData.filter((node) => !node.hidden).map((node) => /* @__PURE__ */ jsx(DriveGridCard, {
51
+ node,
52
+ commands: commands?.node,
53
+ imageLoader: localDriveImageLoader
54
+ }, node.id)) : /* @__PURE__ */ jsx(DriveGridEmpty, { title: "Geen resultaten gevonden" }),
55
+ isFetchingNextPage && Array.from({ length: paginationState?.pageSize ?? 0 }).map((_, index) => /* @__PURE__ */ jsx(DriveGridCardSkeleton, {}, index)),
56
+ /* @__PURE__ */ jsx(DriveGridBottombar, {
57
+ hasNextPage,
58
+ fetchNextPage,
59
+ isFetching,
60
+ isFetchingNextPage
61
+ }),
62
+ commands?.selectedNodes && commands?.selectedNodes.length > 0 && /* @__PURE__ */ jsx(FloatingCommandMenu, {
63
+ data: selectedData,
64
+ commands: commands.selectedNodes,
65
+ meta,
66
+ state: selectedData.length > 0 ? "open" : "closed",
67
+ onSuccess: () => {
68
+ selection?.setRowSelection?.({});
69
+ optimistic?.invalidate?.();
70
+ }
71
+ })
72
+ ]
73
+ });
74
+ }
75
+ function LocalDriveList(props) {
76
+ return /* @__PURE__ */ jsx(DataTable, { ...props });
77
+ }
78
+ function LocalDriveViewLoading({ ...props }) {
79
+ const { view } = useDriveViewContext();
80
+ return /* @__PURE__ */ jsxs("div", {
81
+ ...props,
82
+ children: [view === "grid" && /* @__PURE__ */ jsx(DriveGridLoading, { ...props }), view === "list" && /* @__PURE__ */ jsx(TableSkeleton, { ...props })]
83
+ });
84
+ }
85
+ //#endregion
86
+ export { LocalDriveView, LocalDriveViewLoading, LocalDriveViewProvider };
@@ -0,0 +1,6 @@
1
+ import { LocalDriveNodeWithAsset } from "../lib/validators.mjs";
2
+ import { TableColumnDef } from "@tulip-systems/data-tables";
3
+ //#region src/root/config/columns-data.d.ts
4
+ declare const localDriveColumns: TableColumnDef<LocalDriveNodeWithAsset>[];
5
+ //#endregion
6
+ export { localDriveColumns };
@@ -0,0 +1,62 @@
1
+ "use client";
2
+ import { TableColumnHeader } from "@tulip-systems/data-tables";
3
+ import { TableTextCell, createTableSelectCell } from "@tulip-systems/data-tables/client";
4
+ import { nodeSubtypeConfig, nodeSubtypeVariants } from "@tulip-systems/drive";
5
+ import { useDriveNavigation } from "@tulip-systems/drive/client";
6
+ import { findStatus } from "@tulip-systems/ui/status";
7
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@tulip-systems/ui/tooltip";
8
+ import { FolderIcon } from "lucide-react";
9
+ import Link from "next/link";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ //#region src/root/config/columns-data.tsx
12
+ const localDriveColumns = [
13
+ createTableSelectCell(),
14
+ {
15
+ id: "icon",
16
+ accessorKey: "icon",
17
+ header: () => null,
18
+ cell: ({ row }) => {
19
+ if (row.original.type === "file") {
20
+ const subtype = findStatus(nodeSubtypeConfig, row.original.subtype);
21
+ const Icon = subtype?.icon;
22
+ if (!subtype || !Icon) return null;
23
+ return /* @__PURE__ */ jsx(TableTextCell, {
24
+ className: "w-4",
25
+ children: /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, { children: /* @__PURE__ */ jsx(Icon, { className: nodeSubtypeVariants({
26
+ status: row.original.subtype,
27
+ className: "size-4"
28
+ }) }) }), /* @__PURE__ */ jsx(TooltipContent, { children: subtype.label })] })
29
+ });
30
+ }
31
+ if (row.original.type === "folder") return /* @__PURE__ */ jsx(TableTextCell, {
32
+ className: "w-4",
33
+ children: /* @__PURE__ */ jsx(FolderIcon, { className: "w-4 min-w-4" })
34
+ });
35
+ return null;
36
+ },
37
+ enableSorting: false
38
+ },
39
+ {
40
+ id: "name",
41
+ accessorKey: "name",
42
+ header: ({ column }) => /* @__PURE__ */ jsx(TableColumnHeader, {
43
+ column,
44
+ title: "Naam"
45
+ }),
46
+ cell: ({ row }) => /* @__PURE__ */ jsx(LocalDriveNameCell, { row })
47
+ }
48
+ ];
49
+ function LocalDriveNameCell({ row }) {
50
+ const navigation = useDriveNavigation();
51
+ return /* @__PURE__ */ jsx(TableTextCell, {
52
+ className: "w-full min-w-64",
53
+ children: /* @__PURE__ */ jsx(Link, {
54
+ href: row.original.type === "file" ? row.original.links.view ?? "#" : navigation.getFolderHref(row.original.id),
55
+ className: "truncate hover:underline",
56
+ target: row.original.type === "file" ? "_blank" : "_self",
57
+ children: row.getValue("name")
58
+ })
59
+ });
60
+ }
61
+ //#endregion
62
+ export { localDriveColumns };