@tulip-systems/drive 0.8.3 → 0.10.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/dist/client.d.mts CHANGED
@@ -2,4 +2,5 @@ import { DriveGrid, DriveGridBottombar, DriveGridEmpty, DriveGridEmptyProps, Dri
2
2
  import { DriveGridCard, DriveGridCardSkeleton, DriveGridFileCard, DriveGridFolderCard } from "./components/grid-card.client.mjs";
3
3
  import { DriveSelectionContextValue, DriveSelectionProvider, useDriveSelectionContext } from "./components/selection.client.mjs";
4
4
  import { DriveViewContextValue, DriveViewMode, DriveViewProvider, DriveViewProviderProps, useDriveViewContext } from "./components/view.client.mjs";
5
- export { DriveGrid, DriveGridBottombar, DriveGridCard, DriveGridCardSkeleton, DriveGridEmpty, DriveGridEmptyProps, DriveGridFileCard, DriveGridFolderCard, DriveGridLoading, DriveGridLoadingProps, DriveGridProps, DriveSelectionContextValue, DriveSelectionProvider, DriveViewContextValue, DriveViewMode, DriveViewProvider, DriveViewProviderProps, useDriveSelectionContext, useDriveViewContext };
5
+ import { CreateDriveViewConfigInput, DriveViewCommands, DriveViewConfig, DriveViewConfigProvider, createDriveViewConfig, useDriveViewConfig } from "./lib/view-config.client.mjs";
6
+ export { CreateDriveViewConfigInput, DriveGrid, DriveGridBottombar, DriveGridCard, DriveGridCardSkeleton, DriveGridEmpty, DriveGridEmptyProps, DriveGridFileCard, DriveGridFolderCard, DriveGridLoading, DriveGridLoadingProps, DriveGridProps, DriveSelectionContextValue, DriveSelectionProvider, DriveViewCommands, DriveViewConfig, DriveViewConfigProvider, DriveViewContextValue, DriveViewMode, DriveViewProvider, DriveViewProviderProps, createDriveViewConfig, useDriveSelectionContext, useDriveViewConfig, useDriveViewContext };
package/dist/client.mjs CHANGED
@@ -2,5 +2,6 @@ import { DriveSelectionProvider, useDriveSelectionContext } from "./components/s
2
2
  import { DriveGridCard, DriveGridCardSkeleton, DriveGridFileCard, DriveGridFolderCard } from "./components/grid-card.client.mjs";
3
3
  import { DriveGrid, DriveGridBottombar, DriveGridEmpty, DriveGridLoading } from "./components/grid.client.mjs";
4
4
  import { DriveViewProvider, useDriveViewContext } from "./components/view.client.mjs";
5
+ import { DriveViewConfigProvider, createDriveViewConfig, useDriveViewConfig } from "./lib/view-config.client.mjs";
5
6
 
6
- export { DriveGrid, DriveGridBottombar, DriveGridCard, DriveGridCardSkeleton, DriveGridEmpty, DriveGridFileCard, DriveGridFolderCard, DriveGridLoading, DriveSelectionProvider, DriveViewProvider, useDriveSelectionContext, useDriveViewContext };
7
+ export { DriveGrid, DriveGridBottombar, DriveGridCard, DriveGridCardSkeleton, DriveGridEmpty, DriveGridFileCard, DriveGridFolderCard, DriveGridLoading, DriveSelectionProvider, DriveViewConfigProvider, DriveViewProvider, createDriveViewConfig, useDriveSelectionContext, useDriveViewConfig, useDriveViewContext };
@@ -2,7 +2,7 @@ import { DriveNode } from "../lib/dto.mjs";
2
2
  import { ComponentProps } from "react";
3
3
  import { ImageLoaderProps } from "next/image";
4
4
  import * as react_jsx_runtime0 from "react/jsx-runtime";
5
- import { CommandDef } from "@tulip-systems/core/commands";
5
+ import { CommandFor } from "@tulip-systems/core/commands";
6
6
 
7
7
  //#region src/components/grid-card.client.d.ts
8
8
  /**
@@ -10,7 +10,7 @@ import { CommandDef } from "@tulip-systems/core/commands";
10
10
  */
11
11
  type DriveGridCardProps<TData extends DriveNode> = ComponentProps<"div"> & {
12
12
  node: TData;
13
- commands?: CommandDef<TData>[];
13
+ commands?: CommandFor<TData>[];
14
14
  imageLoader?: (props: ImageLoaderProps) => string;
15
15
  unoptimized?: boolean;
16
16
  };
@@ -0,0 +1,57 @@
1
+ import { Selection, TableColumnDef, TableFiltersResult, TableMetaInput } from "@tulip-systems/core/data-tables";
2
+ import { PropsWithChildren } from "react";
3
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
4
+ import { TableConfigContextValue, useInfiniteStrategy } from "@tulip-systems/core/data-tables/client";
5
+ import { CommandFor } from "@tulip-systems/core/commands";
6
+ import { VisibilityState } from "@tanstack/react-table";
7
+
8
+ //#region src/lib/view-config.client.d.ts
9
+ /**
10
+ * DriveViewConfig context
11
+ */
12
+ type DriveViewCommands<TData, TMeta = object> = {
13
+ node?: CommandFor<TData, TMeta>[];
14
+ selectedNodes?: CommandFor<TData[], TMeta>[];
15
+ };
16
+ type DriveViewConfigContextValue<TData, TMeta = object> = {
17
+ commands?: DriveViewCommands<TData, TMeta>;
18
+ };
19
+ /**
20
+ * Drive View configuration
21
+ */
22
+ type DriveViewConfig<TData, TMeta extends TableMetaInput<TData> = TableMetaInput<TData>> = DriveViewConfigContextValue<TData, TMeta> & Omit<TableConfigContextValue<TData, TableFiltersResult, TMeta>, "commands">;
23
+ type CreateDriveViewConfigInput<TData, TMeta extends TableMetaInput<TData> = TableMetaInput<TData>> = {
24
+ queryData: TData[];
25
+ columns: TableColumnDef<TData>[];
26
+ strategy: ReturnType<typeof useInfiniteStrategy>;
27
+ commands?: DriveViewCommands<TData, TMeta>;
28
+ meta?: TMeta;
29
+ columnVisibility?: VisibilityState;
30
+ selection?: Selection;
31
+ getRowId?: (row: TData) => string;
32
+ };
33
+ declare function createDriveViewConfig<TData, TMeta extends TableMetaInput<TData> = TableMetaInput<TData>>({
34
+ queryData,
35
+ columns,
36
+ strategy,
37
+ commands,
38
+ meta,
39
+ columnVisibility,
40
+ selection,
41
+ getRowId
42
+ }: CreateDriveViewConfigInput<TData, TMeta>): DriveViewConfig<TData, TMeta>;
43
+ /**
44
+ * DriveViewConfigProvider component
45
+ * Wraps the children components with the DriveViewConfigContext provider
46
+ * and provides the configuration for the drive view
47
+ */
48
+ type DriveViewConfigProviderProps<TData, TMeta extends TableMetaInput<TData> = TableMetaInput<TData>> = PropsWithChildren<{
49
+ config: ReturnType<typeof createDriveViewConfig<TData, TMeta>>;
50
+ }>;
51
+ declare function DriveViewConfigProvider<TData, TMeta extends TableMetaInput<TData> = TableMetaInput<TData>>({
52
+ config,
53
+ children
54
+ }: DriveViewConfigProviderProps<TData, TMeta>): react_jsx_runtime0.JSX.Element;
55
+ declare function useDriveViewConfig<TData, TMeta extends TableMetaInput<TData> = TableMetaInput<TData>>(): DriveViewConfig<TData, TMeta>;
56
+ //#endregion
57
+ export { CreateDriveViewConfigInput, DriveViewCommands, DriveViewConfig, DriveViewConfigProvider, createDriveViewConfig, useDriveViewConfig };
@@ -0,0 +1,46 @@
1
+ "use client";
2
+
3
+ import { createContext, use } from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { TableConfigProvider, createTableConfig, useTableConfigContext } from "@tulip-systems/core/data-tables/client";
6
+
7
+ //#region src/lib/view-config.client.tsx
8
+ const DriveViewConfigContext = createContext({});
9
+ function createDriveViewConfig({ queryData, columns, strategy, commands, meta, columnVisibility, selection, getRowId = (row) => row.id }) {
10
+ const { commands: _commands, ...table } = createTableConfig({
11
+ queryData,
12
+ columns,
13
+ getRowId,
14
+ strategy,
15
+ meta,
16
+ columnVisibility,
17
+ selection
18
+ });
19
+ return {
20
+ ...table,
21
+ commands
22
+ };
23
+ }
24
+ function DriveViewConfigProvider({ config, children }) {
25
+ return /* @__PURE__ */ jsx(DriveViewConfigContext, {
26
+ value: config,
27
+ children: /* @__PURE__ */ jsx(TableConfigProvider, {
28
+ config: {
29
+ ...config,
30
+ commands: config.commands?.selectedNodes
31
+ },
32
+ children
33
+ })
34
+ });
35
+ }
36
+ function useDriveViewConfig() {
37
+ const tableConfig = useTableConfigContext();
38
+ const viewConfig = use(DriveViewConfigContext);
39
+ return {
40
+ ...tableConfig,
41
+ ...viewConfig
42
+ };
43
+ }
44
+
45
+ //#endregion
46
+ export { DriveViewConfigProvider, createDriveViewConfig, useDriveViewConfig };
@@ -1,9 +1,9 @@
1
+ import { DriveViewCommands } from "../../../lib/view-config.client.mjs";
1
2
  import { GoogleDriveNode } from "../lib/validators.mjs";
2
3
  import { TableColumnDef } from "@tulip-systems/core/data-tables";
3
4
  import { ComponentProps } from "react";
4
5
  import * as react_jsx_runtime0 from "react/jsx-runtime";
5
6
  import { useInfiniteStrategy } from "@tulip-systems/core/data-tables/client";
6
- import { CommandDef } from "@tulip-systems/core/commands";
7
7
  import { VisibilityState } from "@tanstack/react-table";
8
8
 
9
9
  //#region src/providers/google/components/view.client.d.ts
@@ -14,7 +14,7 @@ type GoogleDriveViewProviderProps<TData extends GoogleDriveNode = GoogleDriveNod
14
14
  queryData: TData[];
15
15
  columns?: TableColumnDef<TData>[];
16
16
  strategy: ReturnType<typeof useInfiniteStrategy>;
17
- commands?: CommandDef<TData>[];
17
+ commands?: DriveViewCommands<TData>;
18
18
  columnVisibility?: VisibilityState;
19
19
  };
20
20
  declare function GoogleDriveViewProvider<TData extends GoogleDriveNode = GoogleDriveNode>({
@@ -4,27 +4,27 @@ import { useDriveSelectionContext } from "../../../components/selection.client.m
4
4
  import { DriveGridCard, DriveGridCardSkeleton } from "../../../components/grid-card.client.mjs";
5
5
  import { DriveGrid, DriveGridBottombar, DriveGridEmpty, DriveGridLoading } from "../../../components/grid.client.mjs";
6
6
  import { useDriveViewContext } from "../../../components/view.client.mjs";
7
+ import { DriveViewConfigProvider, createDriveViewConfig, useDriveViewConfig } from "../../../lib/view-config.client.mjs";
7
8
  import { googleDriveColumns } from "../config/columns-data.mjs";
8
9
  import { useGoogleDriveContext } from "./provider.client.mjs";
9
10
  import { TableLayout, TableSkeleton } from "@tulip-systems/core/data-tables";
10
11
  import { useMemo } from "react";
11
12
  import { FloatingCommandMenu } from "@tulip-systems/core/commands/client";
12
13
  import { jsx, jsxs } from "react/jsx-runtime";
13
- import { DataTable, TableConfigProvider, createTableConfig, useTableConfigContext } from "@tulip-systems/core/data-tables/client";
14
+ import { DataTable } from "@tulip-systems/core/data-tables/client";
14
15
 
15
16
  //#region src/providers/google/components/view.client.tsx
16
17
  function GoogleDriveViewProvider({ queryData, columns = googleDriveColumns, strategy, commands, columnVisibility, children, ...props }) {
17
18
  const { meta } = useGoogleDriveContext();
18
- const { selection } = useDriveSelectionContext();
19
- return /* @__PURE__ */ jsx(TableConfigProvider, {
20
- config: createTableConfig({
19
+ return /* @__PURE__ */ jsx(DriveViewConfigProvider, {
20
+ config: createDriveViewConfig({
21
21
  queryData,
22
22
  columns,
23
23
  strategy,
24
24
  commands,
25
25
  meta,
26
26
  columnVisibility,
27
- selection
27
+ selection: useDriveSelectionContext()?.selection
28
28
  }),
29
29
  children: /* @__PURE__ */ jsx(TableLayout, {
30
30
  ...props,
@@ -45,7 +45,7 @@ function GoogleDriveView() {
45
45
  * GoogleDriveGrid
46
46
  */
47
47
  function GoogleDriveGrid(props) {
48
- const { queryData, strategy, commands, selection, meta } = useTableConfigContext();
48
+ const { queryData, strategy, commands, selection, meta } = useDriveViewConfig();
49
49
  const { rowCount, paginationState } = strategy;
50
50
  const { isFetching, isFetchingNextPage, fetchNextPage } = strategy.meta;
51
51
  const hasNextPage = rowCount == null ? false : queryData.length < rowCount;
@@ -55,7 +55,7 @@ function GoogleDriveGrid(props) {
55
55
  children: [
56
56
  queryData.length > 0 ? queryData.map((node) => /* @__PURE__ */ jsx(DriveGridCard, {
57
57
  node,
58
- commands,
58
+ commands: commands?.node,
59
59
  unoptimized: true
60
60
  }, node.id)) : /* @__PURE__ */ jsx(DriveGridEmpty, { title: "Geen resultaten gevonden" }),
61
61
  isFetchingNextPage && Array.from({ length: paginationState?.pageSize ?? 0 }).map((_, index) => /* @__PURE__ */ jsx(DriveGridCardSkeleton, {}, index)),
@@ -65,9 +65,9 @@ function GoogleDriveGrid(props) {
65
65
  isFetching,
66
66
  isFetchingNextPage
67
67
  }),
68
- commands && commands.length > 0 && /* @__PURE__ */ jsx(FloatingCommandMenu, {
68
+ commands?.selectedNodes && commands.selectedNodes.length > 0 && /* @__PURE__ */ jsx(FloatingCommandMenu, {
69
69
  data: selectedData,
70
- commands,
70
+ commands: commands.selectedNodes,
71
71
  meta,
72
72
  state: selectedData.length > 0 ? "open" : "closed",
73
73
  onSuccess: () => selection?.setRowSelection?.({})
@@ -6,8 +6,8 @@ import { TableColumnHeader } from "@tulip-systems/core/data-tables";
6
6
  import { findStatus } from "@tulip-systems/core/components";
7
7
  import { FolderIcon } from "lucide-react";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
- import { Tooltip, TooltipContent, TooltipTrigger } from "@tulip-systems/core/components/client";
10
9
  import { TableTextCell, createTableSelectCell } from "@tulip-systems/core/data-tables/client";
10
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@tulip-systems/core/components/client";
11
11
  import Link from "next/link";
12
12
  import { createSerializer, useQueryStates } from "nuqs";
13
13
 
@@ -315,7 +315,7 @@ declare function createGoogleDriveProcedures<TSchema extends TDatabaseSchema>(dr
315
315
  trashedAt: Date | null;
316
316
  googleParents: string[];
317
317
  canEdit: boolean | null;
318
- }, "id" | "name" | "parentId"> & {
318
+ }, "name" | "parentId" | "id"> & {
319
319
  depth: number;
320
320
  })[], (Pick<{
321
321
  id: string;
@@ -348,7 +348,7 @@ declare function createGoogleDriveProcedures<TSchema extends TDatabaseSchema>(dr
348
348
  trashedAt: Date | null;
349
349
  googleParents: string[];
350
350
  canEdit: boolean | null;
351
- }, "id" | "name" | "parentId"> & {
351
+ }, "name" | "parentId" | "id"> & {
352
352
  depth: number;
353
353
  })[]>, Record<never, never>, Record<never, never>>;
354
354
  createFolder: _orpc_server0.DecoratedProcedure<_orpc_server0.MergedInitialContext<_tulip_systems_core_router_server0.RPCContext<TSchema> & Record<never, never>, _tulip_systems_core_router_server0.RPCContext<TSchema> & Record<never, never>, _tulip_systems_core_router_server0.RPCContext<TSchema>>, _orpc_server0.MergedCurrentContext<_tulip_systems_core_router_server0.RPCContext<TSchema>, _tulip_systems_core_router_server0.ProtectedRPCContext<TSchema>>, z.ZodObject<{
@@ -1,9 +1,9 @@
1
+ import { DriveViewCommands } from "../../../lib/view-config.client.mjs";
1
2
  import { LocalDriveNodeWithAsset } from "../lib/validators.mjs";
2
3
  import { TableColumnDef } from "@tulip-systems/core/data-tables";
3
4
  import { ComponentProps } from "react";
4
5
  import * as react_jsx_runtime0 from "react/jsx-runtime";
5
6
  import { useInfiniteStrategy } from "@tulip-systems/core/data-tables/client";
6
- import { CommandDef } from "@tulip-systems/core/commands";
7
7
  import { VisibilityState } from "@tanstack/react-table";
8
8
 
9
9
  //#region src/providers/local/components/view.client.d.ts
@@ -11,7 +11,7 @@ type LocalDriveViewProviderProps<TData extends LocalDriveNodeWithAsset = LocalDr
11
11
  queryData: TData[];
12
12
  columns?: TableColumnDef<TData>[];
13
13
  strategy: ReturnType<typeof useInfiniteStrategy>;
14
- commands?: CommandDef<TData>[];
14
+ commands?: DriveViewCommands<TData>;
15
15
  columnVisibility?: VisibilityState;
16
16
  };
17
17
  declare function LocalDriveViewProvider<TData extends LocalDriveNodeWithAsset = LocalDriveNodeWithAsset>({
@@ -4,6 +4,7 @@ import { useDriveSelectionContext } from "../../../components/selection.client.m
4
4
  import { DriveGridCard, DriveGridCardSkeleton } from "../../../components/grid-card.client.mjs";
5
5
  import { DriveGrid, DriveGridBottombar, DriveGridEmpty, DriveGridLoading } from "../../../components/grid.client.mjs";
6
6
  import { useDriveViewContext } from "../../../components/view.client.mjs";
7
+ import { DriveViewConfigProvider, createDriveViewConfig, useDriveViewConfig } from "../../../lib/view-config.client.mjs";
7
8
  import { localDriveColumns } from "../config/columns-data.mjs";
8
9
  import { localDriveImageLoader } from "../lib/helpers.mjs";
9
10
  import { useLocalDriveUploadZone } from "./upload-zone-context.client.mjs";
@@ -12,21 +13,20 @@ import { TableLayout, TableSkeleton } from "@tulip-systems/core/data-tables";
12
13
  import { useMemo } from "react";
13
14
  import { FloatingCommandMenu } from "@tulip-systems/core/commands/client";
14
15
  import { jsx, jsxs } from "react/jsx-runtime";
15
- import { DataTable, TableConfigProvider, createTableConfig, useTableConfigContext } from "@tulip-systems/core/data-tables/client";
16
+ import { DataTable } from "@tulip-systems/core/data-tables/client";
16
17
 
17
18
  //#region src/providers/local/components/view.client.tsx
18
19
  function LocalDriveViewProvider({ queryData, columns = localDriveColumns, strategy, commands, columnVisibility, children, ...props }) {
19
20
  const { meta } = useLocalDriveContext();
20
- const { selection } = useDriveSelectionContext();
21
- return /* @__PURE__ */ jsx(TableConfigProvider, {
22
- config: createTableConfig({
21
+ return /* @__PURE__ */ jsx(DriveViewConfigProvider, {
22
+ config: createDriveViewConfig({
23
23
  queryData,
24
24
  columns,
25
25
  strategy,
26
26
  commands,
27
27
  meta,
28
28
  columnVisibility,
29
- selection
29
+ selection: useDriveSelectionContext()?.selection
30
30
  }),
31
31
  children: /* @__PURE__ */ jsx(TableLayout, {
32
32
  ...props,
@@ -41,7 +41,7 @@ function LocalDriveView() {
41
41
  return null;
42
42
  }
43
43
  function LocalDriveGrid(props) {
44
- const { queryData, strategy, commands, selection, meta } = useTableConfigContext();
44
+ const { queryData, strategy, commands, selection, meta } = useDriveViewConfig();
45
45
  const { optimistic } = useLocalDriveUploadZone();
46
46
  const { rowCount, paginationState } = strategy;
47
47
  const { isFetching, isFetchingNextPage, fetchNextPage } = strategy.meta;
@@ -52,7 +52,7 @@ function LocalDriveGrid(props) {
52
52
  children: [
53
53
  queryData.length > 0 ? queryData.filter((node) => !node.hidden).map((node) => /* @__PURE__ */ jsx(DriveGridCard, {
54
54
  node,
55
- commands,
55
+ commands: commands?.node,
56
56
  imageLoader: localDriveImageLoader
57
57
  }, node.id)) : /* @__PURE__ */ jsx(DriveGridEmpty, { title: "Geen resultaten gevonden" }),
58
58
  isFetchingNextPage && Array.from({ length: paginationState?.pageSize ?? 0 }).map((_, index) => /* @__PURE__ */ jsx(DriveGridCardSkeleton, {}, index)),
@@ -62,9 +62,9 @@ function LocalDriveGrid(props) {
62
62
  isFetching,
63
63
  isFetchingNextPage
64
64
  }),
65
- commands && commands.length > 0 && /* @__PURE__ */ jsx(FloatingCommandMenu, {
65
+ commands?.selectedNodes && commands?.selectedNodes.length > 0 && /* @__PURE__ */ jsx(FloatingCommandMenu, {
66
66
  data: selectedData,
67
- commands,
67
+ commands: commands.selectedNodes,
68
68
  meta,
69
69
  state: selectedData.length > 0 ? "open" : "closed",
70
70
  onSuccess: () => {
@@ -6,8 +6,8 @@ import { TableColumnHeader } from "@tulip-systems/core/data-tables";
6
6
  import { findStatus } from "@tulip-systems/core/components";
7
7
  import { FolderIcon } from "lucide-react";
8
8
  import { jsx, jsxs } from "react/jsx-runtime";
9
- import { Tooltip, TooltipContent, TooltipTrigger } from "@tulip-systems/core/components/client";
10
9
  import { TableTextCell, createTableSelectCell } from "@tulip-systems/core/data-tables/client";
10
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@tulip-systems/core/components/client";
11
11
  import Link from "next/link";
12
12
  import { createSerializer, useQueryStates } from "nuqs";
13
13
 
@@ -0,0 +1,16 @@
1
+ import { nodes } from "../lib/schema.mjs";
2
+ import { asc, getTableColumns } from "drizzle-orm";
3
+ import { createTableQuerySortingParser } from "@tulip-systems/core/data-tables/server";
4
+
5
+ //#region src/providers/local/config/sorting.ts
6
+ /**
7
+ * Local Drive specific sorting config
8
+ */
9
+ const localDriveTableQuerySortingConfig = getTableColumns(nodes);
10
+ /**
11
+ * Local Drive specific sorting parser
12
+ */
13
+ const parseLocalDriveTableQuerySorting = createTableQuerySortingParser(localDriveTableQuerySortingConfig, { fallback: asc(nodes.createdAt) });
14
+
15
+ //#endregion
16
+ export { parseLocalDriveTableQuerySorting };
@@ -13944,38 +13944,38 @@ declare function createLocalDriveProcedures(drive: LocalDrive<DriveSchema>): {
13944
13944
  id: z.ZodNullable<z.ZodString>;
13945
13945
  namespace: z.ZodString;
13946
13946
  }, z.core.$strip>, _orpc_contract0.Schema<(Pick<{
13947
- id: string;
13948
- createdAt: Date;
13949
- updatedAt: Date;
13950
13947
  name: string;
13948
+ namespace: string;
13951
13949
  type: "file" | "folder" | null;
13952
- readonly: boolean | null;
13950
+ subtype: "image" | "document" | "spreadsheet" | "video" | "audio" | "archive" | "other";
13953
13951
  size: number | null;
13954
13952
  contentType: string | null;
13955
- namespace: string;
13956
- subtype: "image" | "document" | "spreadsheet" | "video" | "audio" | "archive" | "other";
13953
+ readonly: boolean | null;
13957
13954
  hidden: boolean | null;
13958
13955
  archivedAt: Date | null;
13959
13956
  parentId: string | null;
13960
- assetId: string | null;
13961
- }, "id" | "name" | "parentId"> & {
13962
- depth: number;
13963
- })[], (Pick<{
13964
13957
  id: string;
13965
13958
  createdAt: Date;
13966
13959
  updatedAt: Date;
13960
+ assetId: string | null;
13961
+ }, "name" | "parentId" | "id"> & {
13962
+ depth: number;
13963
+ })[], (Pick<{
13967
13964
  name: string;
13965
+ namespace: string;
13968
13966
  type: "file" | "folder" | null;
13969
- readonly: boolean | null;
13967
+ subtype: "image" | "document" | "spreadsheet" | "video" | "audio" | "archive" | "other";
13970
13968
  size: number | null;
13971
13969
  contentType: string | null;
13972
- namespace: string;
13973
- subtype: "image" | "document" | "spreadsheet" | "video" | "audio" | "archive" | "other";
13970
+ readonly: boolean | null;
13974
13971
  hidden: boolean | null;
13975
13972
  archivedAt: Date | null;
13976
13973
  parentId: string | null;
13974
+ id: string;
13975
+ createdAt: Date;
13976
+ updatedAt: Date;
13977
13977
  assetId: string | null;
13978
- }, "id" | "name" | "parentId"> & {
13978
+ }, "name" | "parentId" | "id"> & {
13979
13979
  depth: number;
13980
13980
  })[]>, Record<never, never>, Record<never, never>>;
13981
13981
  /**
@@ -19473,19 +19473,19 @@ declare function createLocalDriveProcedures(drive: LocalDrive<DriveSchema>): {
19473
19473
  presignedUrl: string;
19474
19474
  node: LocalDriveFileNode;
19475
19475
  asset: {
19476
+ contentType: string | null;
19477
+ size: number | null;
19478
+ metadata: unknown;
19479
+ key: string;
19480
+ status: "error" | "pending" | "ready";
19476
19481
  id: string;
19477
19482
  createdAt: Date;
19478
19483
  updatedAt: Date;
19479
19484
  name: string | null;
19480
- key: string;
19481
- metadata: unknown;
19482
19485
  provider: "s3";
19483
- uploadId: string;
19484
- visibility: "private" | "public";
19485
- size: number | null;
19486
- contentType: string | null;
19487
19486
  bucket: string;
19488
- status: "error" | "pending" | "ready";
19487
+ visibility: "private" | "public";
19488
+ uploadId: string;
19489
19489
  etag: string | null;
19490
19490
  uploadedAt: Date;
19491
19491
  deletedAt: Date | null;
@@ -19495,19 +19495,19 @@ declare function createLocalDriveProcedures(drive: LocalDrive<DriveSchema>): {
19495
19495
  presignedUrl: string;
19496
19496
  node: LocalDriveFileNode;
19497
19497
  asset: {
19498
+ contentType: string | null;
19499
+ size: number | null;
19500
+ metadata: unknown;
19501
+ key: string;
19502
+ status: "error" | "pending" | "ready";
19498
19503
  id: string;
19499
19504
  createdAt: Date;
19500
19505
  updatedAt: Date;
19501
19506
  name: string | null;
19502
- key: string;
19503
- metadata: unknown;
19504
19507
  provider: "s3";
19505
- uploadId: string;
19506
- visibility: "private" | "public";
19507
- size: number | null;
19508
- contentType: string | null;
19509
19508
  bucket: string;
19510
- status: "error" | "pending" | "ready";
19509
+ visibility: "private" | "public";
19510
+ uploadId: string;
19511
19511
  etag: string | null;
19512
19512
  uploadedAt: Date;
19513
19513
  deletedAt: Date | null;
@@ -104,21 +104,21 @@ declare class LocalDrive<TSchema extends TDatabaseSchema> implements DriveReader
104
104
  id: string | null;
105
105
  namespace: string;
106
106
  }): Promise<(Pick<{
107
- id: string;
108
- createdAt: Date;
109
- updatedAt: Date;
110
107
  name: string;
108
+ namespace: string;
111
109
  type: "file" | "folder" | null;
112
- readonly: boolean | null;
110
+ subtype: "image" | "document" | "spreadsheet" | "video" | "audio" | "archive" | "other";
113
111
  size: number | null;
114
112
  contentType: string | null;
115
- namespace: string;
116
- subtype: "image" | "document" | "spreadsheet" | "video" | "audio" | "archive" | "other";
113
+ readonly: boolean | null;
117
114
  hidden: boolean | null;
118
115
  archivedAt: Date | null;
119
116
  parentId: string | null;
117
+ id: string;
118
+ createdAt: Date;
119
+ updatedAt: Date;
120
120
  assetId: string | null;
121
- }, "id" | "name" | "parentId"> & {
121
+ }, "name" | "parentId" | "id"> & {
122
122
  depth: number;
123
123
  })[]>;
124
124
  /**
@@ -247,19 +247,19 @@ declare class LocalDrive<TSchema extends TDatabaseSchema> implements DriveReader
247
247
  presignedUrl: string;
248
248
  node: LocalDriveFileNode;
249
249
  asset: {
250
+ contentType: string | null;
251
+ size: number | null;
252
+ metadata: unknown;
253
+ key: string;
254
+ status: "error" | "pending" | "ready";
250
255
  id: string;
251
256
  createdAt: Date;
252
257
  updatedAt: Date;
253
258
  name: string | null;
254
- key: string;
255
- metadata: unknown;
256
259
  provider: "s3";
257
- uploadId: string;
258
- visibility: "private" | "public";
259
- size: number | null;
260
- contentType: string | null;
261
260
  bucket: string;
262
- status: "error" | "pending" | "ready";
261
+ visibility: "private" | "public";
262
+ uploadId: string;
263
263
  etag: string | null;
264
264
  uploadedAt: Date;
265
265
  deletedAt: Date | null;
@@ -2,12 +2,13 @@ import { deviceSizes } from "./constants.mjs";
2
2
  import { inferLocalDriveNodeSubtype, isLocalDriveFile, isLocalDriveFolder, toLocalDriveNode } from "./helpers.mjs";
3
3
  import { nodePresignedUrls, nodeVariants, nodes } from "./schema.mjs";
4
4
  import { getLocalFileURLSchemaDefaults } from "./validators.mjs";
5
+ import { parseLocalDriveTableQuerySorting } from "../config/sorting.mjs";
5
6
  import { storageAssets } from "@tulip-systems/core/storage";
6
- import { and, asc, desc, eq, getTableColumns, inArray, isNotNull, isNull, sql } from "drizzle-orm";
7
+ import { and, eq, getTableColumns, inArray, isNotNull, isNull, sql } from "drizzle-orm";
7
8
  import { ServerError } from "@tulip-systems/core/router/server";
8
9
  import { after } from "next/server";
9
10
  import stream from "node:stream/consumers";
10
- import { convertOrderByToQueryParams, convertSearchToQueryParams, createTableQueryResponse } from "@tulip-systems/core/data-tables/server";
11
+ import { convertSearchToQueryParams, createTableQueryResponse } from "@tulip-systems/core/data-tables/server";
11
12
  import { addSeconds } from "date-fns";
12
13
 
13
14
  //#region src/providers/local/lib/service.server.ts
@@ -105,11 +106,11 @@ var LocalDrive = class {
105
106
  * @returns A promise resolving to the matching child nodes.
106
107
  */
107
108
  async getNodesByParentId({ filters, ...query }) {
108
- const orderBy = convertOrderByToQueryParams(query, nodes, asc(nodes.createdAt));
109
+ const orderBy = parseLocalDriveTableQuerySorting.parse(query);
109
110
  const search = convertSearchToQueryParams(query, [nodes.name]);
110
111
  const archivedFilter = filters.isArchived === true ? isNotNull(nodes.archivedAt) : filters.isArchived === false ? isNull(nodes.archivedAt) : void 0;
111
112
  const parentFilter = filters.parentId ? eq(nodes.parentId, filters.parentId) : isNull(nodes.parentId);
112
- return (await this.#db.select().from(nodes).where(and(filters.nodeIds != null ? inArray(nodes.id, filters.nodeIds) : void 0, filters.types != null ? inArray(nodes.type, filters.types) : void 0, archivedFilter, filters.hidden != null ? eq(nodes.hidden, filters.hidden) : void 0, parentFilter, eq(nodes.namespace, filters.namespace), search)).orderBy(orderBy)).map(toLocalDriveNode);
113
+ return (await this.#db.select().from(nodes).where(and(filters.nodeIds != null ? inArray(nodes.id, filters.nodeIds) : void 0, filters.types != null ? inArray(nodes.type, filters.types) : void 0, archivedFilter, filters.hidden != null ? eq(nodes.hidden, filters.hidden) : void 0, parentFilter, eq(nodes.namespace, filters.namespace), search)).orderBy(...orderBy)).map(toLocalDriveNode);
113
114
  }
114
115
  /**
115
116
  * Lists tree-scoped nodes with pagination, search, and richer local filters.
@@ -121,7 +122,7 @@ var LocalDrive = class {
121
122
  * @returns A paginated table-query response.
122
123
  */
123
124
  async listTree({ filters, ...query }) {
124
- const orderBy = convertOrderByToQueryParams(query, nodes, desc(nodes.createdAt));
125
+ const orderBy = parseLocalDriveTableQuerySorting.parse(query);
125
126
  const search = convertSearchToQueryParams(query, [nodes.name]);
126
127
  const archivedFilter = filters.isArchived === true ? isNotNull(nodes.archivedAt) : filters.isArchived === false ? isNull(nodes.archivedAt) : void 0;
127
128
  const parentFilter = filters.parentId ? eq(nodes.parentId, filters.parentId) : isNull(nodes.parentId);
@@ -132,7 +133,7 @@ var LocalDrive = class {
132
133
  return [await tx.select({
133
134
  ...getTableColumns(nodes),
134
135
  asset: storageAssets
135
- }).from(nodes).where(where).leftJoin(storageAssets, eq(nodes.assetId, storageAssets.id)).orderBy(orderBy).limit(limit).offset(offset), await tx.$count(nodes, where)];
136
+ }).from(nodes).where(where).leftJoin(storageAssets, eq(nodes.assetId, storageAssets.id)).orderBy(...orderBy).limit(limit).offset(offset), await tx.$count(nodes, where)];
136
137
  });
137
138
  return createTableQueryResponse({
138
139
  data: data.map(({ asset, ...node }) => ({
@@ -153,7 +154,7 @@ var LocalDrive = class {
153
154
  * @returns A paginated table-query response.
154
155
  */
155
156
  async listFlat({ filters, ...query }) {
156
- const orderBy = convertOrderByToQueryParams(query, nodes, desc(nodes.createdAt));
157
+ const orderBy = parseLocalDriveTableQuerySorting.parse(query);
157
158
  const search = convertSearchToQueryParams(query, [nodes.name]);
158
159
  const archivedFilter = filters.isArchived === true ? isNotNull(nodes.archivedAt) : filters.isArchived === false ? isNull(nodes.archivedAt) : void 0;
159
160
  const limit = query.limit;
@@ -163,7 +164,7 @@ var LocalDrive = class {
163
164
  return [await tx.select({
164
165
  ...getTableColumns(nodes),
165
166
  asset: storageAssets
166
- }).from(nodes).where(where).leftJoin(storageAssets, eq(nodes.assetId, storageAssets.id)).orderBy(orderBy).limit(limit).offset(offset), await tx.$count(nodes, where)];
167
+ }).from(nodes).where(where).leftJoin(storageAssets, eq(nodes.assetId, storageAssets.id)).orderBy(...orderBy).limit(limit).offset(offset), await tx.$count(nodes, where)];
167
168
  });
168
169
  return createTableQueryResponse({
169
170
  data: data.map(({ asset, ...node }) => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tulip-systems/drive",
3
- "version": "0.8.3",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "license": "AGPL-3.0",
@@ -65,7 +65,7 @@
65
65
  "uuid": "^14.0.0",
66
66
  "vaul": "^1.1.2",
67
67
  "zod": "^4.4.3",
68
- "@tulip-systems/core": "0.8.3"
68
+ "@tulip-systems/core": "0.10.0"
69
69
  },
70
70
  "peerDependencies": {
71
71
  "@tailwindcss/typography": "^0.5.19",
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { useDraggable, useDroppable } from "@dnd-kit/react";
4
- import type { CommandDef } from "@tulip-systems/core/commands";
4
+ import type { CommandFor } from "@tulip-systems/core/commands";
5
5
  import {
6
6
  ContextCommandMenu,
7
7
  ContextCommandMenuContent,
@@ -29,7 +29,7 @@ import { useDriveSelectionContext } from "./selection.client";
29
29
  */
30
30
  type DriveGridCardProps<TData extends DriveNode> = ComponentProps<"div"> & {
31
31
  node: TData;
32
- commands?: CommandDef<TData>[];
32
+ commands?: CommandFor<TData>[];
33
33
  imageLoader?: (props: ImageLoaderProps) => string;
34
34
  unoptimized?: boolean;
35
35
  };
@@ -5,3 +5,8 @@ export * from "@/components/grid-card.client";
5
5
  */
6
6
  export * from "@/components/selection.client";
7
7
  export * from "@/components/view.client";
8
+
9
+ /**
10
+ * Lib
11
+ */
12
+ export * from "@/lib/view-config.client";
@@ -0,0 +1,116 @@
1
+ "use client";
2
+
3
+ import type { VisibilityState } from "@tanstack/react-table";
4
+ import type { CommandFor } from "@tulip-systems/core/commands";
5
+ import type {
6
+ Selection,
7
+ TableColumnDef,
8
+ TableFiltersResult,
9
+ TableMetaInput,
10
+ } from "@tulip-systems/core/data-tables";
11
+ import {
12
+ createTableConfig,
13
+ type TableConfigContextValue,
14
+ TableConfigProvider,
15
+ type useInfiniteStrategy,
16
+ useTableConfigContext,
17
+ } from "@tulip-systems/core/data-tables/client";
18
+ import { createContext, type PropsWithChildren, use } from "react";
19
+
20
+ /**
21
+ * DriveViewConfig context
22
+ */
23
+ export type DriveViewCommands<TData, TMeta = object> = {
24
+ node?: CommandFor<TData, TMeta>[];
25
+ selectedNodes?: CommandFor<TData[], TMeta>[];
26
+ };
27
+
28
+ type DriveViewConfigContextValue<TData, TMeta = object> = {
29
+ commands?: DriveViewCommands<TData, TMeta>;
30
+ };
31
+
32
+ const DriveViewConfigContext = createContext({} as DriveViewConfigContextValue<any, any>);
33
+
34
+ /**
35
+ * Drive View configuration
36
+ */
37
+ export type DriveViewConfig<
38
+ TData,
39
+ TMeta extends TableMetaInput<TData> = TableMetaInput<TData>,
40
+ > = DriveViewConfigContextValue<TData, TMeta> &
41
+ Omit<TableConfigContextValue<TData, TableFiltersResult, TMeta>, "commands">;
42
+
43
+ export type CreateDriveViewConfigInput<
44
+ TData,
45
+ TMeta extends TableMetaInput<TData> = TableMetaInput<TData>,
46
+ > = {
47
+ queryData: TData[];
48
+ columns: TableColumnDef<TData>[];
49
+ strategy: ReturnType<typeof useInfiniteStrategy>;
50
+ commands?: DriveViewCommands<TData, TMeta>;
51
+ meta?: TMeta;
52
+ columnVisibility?: VisibilityState;
53
+ selection?: Selection;
54
+ getRowId?: (row: TData) => string;
55
+ };
56
+
57
+ export function createDriveViewConfig<
58
+ TData,
59
+ TMeta extends TableMetaInput<TData> = TableMetaInput<TData>,
60
+ >({
61
+ queryData,
62
+ columns,
63
+ strategy,
64
+ commands,
65
+ meta,
66
+ columnVisibility,
67
+ selection,
68
+ getRowId = (row) => (row as { id: string }).id,
69
+ }: CreateDriveViewConfigInput<TData, TMeta>) {
70
+ const { commands: _commands, ...table } = createTableConfig<TData, TableFiltersResult, TMeta>({
71
+ queryData,
72
+ columns,
73
+ getRowId,
74
+ strategy,
75
+ meta,
76
+ columnVisibility,
77
+ selection,
78
+ });
79
+
80
+ return { ...table, commands } as DriveViewConfig<TData, TMeta>;
81
+ }
82
+
83
+ /**
84
+ * DriveViewConfigProvider component
85
+ * Wraps the children components with the DriveViewConfigContext provider
86
+ * and provides the configuration for the drive view
87
+ */
88
+ type DriveViewConfigProviderProps<
89
+ TData,
90
+ TMeta extends TableMetaInput<TData> = TableMetaInput<TData>,
91
+ > = PropsWithChildren<{
92
+ config: ReturnType<typeof createDriveViewConfig<TData, TMeta>>;
93
+ }>;
94
+
95
+ export function DriveViewConfigProvider<
96
+ TData,
97
+ TMeta extends TableMetaInput<TData> = TableMetaInput<TData>,
98
+ >({ config, children }: DriveViewConfigProviderProps<TData, TMeta>) {
99
+ return (
100
+ <DriveViewConfigContext value={config}>
101
+ <TableConfigProvider config={{ ...config, commands: config.commands?.selectedNodes }}>
102
+ {children}
103
+ </TableConfigProvider>
104
+ </DriveViewConfigContext>
105
+ );
106
+ }
107
+
108
+ export function useDriveViewConfig<
109
+ TData,
110
+ TMeta extends TableMetaInput<TData> = TableMetaInput<TData>,
111
+ >() {
112
+ const tableConfig = useTableConfigContext<TData, TableFiltersResult, TMeta>();
113
+ const viewConfig = use(DriveViewConfigContext) as DriveViewConfigContextValue<TData, TMeta>;
114
+
115
+ return { ...tableConfig, ...viewConfig } as DriveViewConfig<TData, TMeta>;
116
+ }
@@ -1,16 +1,12 @@
1
1
  "use client";
2
2
 
3
3
  import type { VisibilityState } from "@tanstack/react-table";
4
- import type { CommandDef } from "@tulip-systems/core/commands";
5
4
  import { FloatingCommandMenu } from "@tulip-systems/core/commands/client";
6
5
  import { type TableColumnDef, TableLayout, TableSkeleton } from "@tulip-systems/core/data-tables";
7
6
  import {
8
- createTableConfig,
9
7
  DataTable,
10
8
  type InfiniteStrategyMeta,
11
- TableConfigProvider,
12
9
  type useInfiniteStrategy,
13
- useTableConfigContext,
14
10
  } from "@tulip-systems/core/data-tables/client";
15
11
  import { type ComponentProps, useMemo } from "react";
16
12
  import {
@@ -22,6 +18,12 @@ import {
22
18
  import { DriveGridCard, DriveGridCardSkeleton } from "@/components/grid-card.client";
23
19
  import { useDriveSelectionContext } from "@/components/selection.client";
24
20
  import { useDriveViewContext } from "@/components/view.client";
21
+ import {
22
+ createDriveViewConfig,
23
+ type DriveViewCommands,
24
+ DriveViewConfigProvider,
25
+ useDriveViewConfig,
26
+ } from "@/lib/view-config.client";
25
27
  import { googleDriveColumns } from "../config/columns-data";
26
28
  import type { GoogleDriveNode } from "../lib/validators";
27
29
  import { useGoogleDriveContext } from "./provider.client";
@@ -34,7 +36,7 @@ type GoogleDriveViewProviderProps<TData extends GoogleDriveNode = GoogleDriveNod
34
36
  queryData: TData[];
35
37
  columns?: TableColumnDef<TData>[];
36
38
  strategy: ReturnType<typeof useInfiniteStrategy>;
37
- commands?: CommandDef<TData>[];
39
+ commands?: DriveViewCommands<TData>;
38
40
  columnVisibility?: VisibilityState;
39
41
  };
40
42
 
@@ -48,25 +50,21 @@ export function GoogleDriveViewProvider<TData extends GoogleDriveNode = GoogleDr
48
50
  ...props
49
51
  }: GoogleDriveViewProviderProps<TData>) {
50
52
  const { meta } = useGoogleDriveContext();
51
- const { selection } = useDriveSelectionContext();
52
-
53
- /**
54
- * Table
55
- */
56
- const config = createTableConfig<TData>({
53
+ const selectionContext = useDriveSelectionContext();
54
+ const config = createDriveViewConfig<TData>({
57
55
  queryData,
58
56
  columns,
59
57
  strategy,
60
58
  commands,
61
59
  meta,
62
60
  columnVisibility,
63
- selection,
61
+ selection: selectionContext?.selection,
64
62
  });
65
63
 
66
64
  return (
67
- <TableConfigProvider config={config}>
65
+ <DriveViewConfigProvider config={config}>
68
66
  <TableLayout {...props}>{children}</TableLayout>
69
- </TableConfigProvider>
67
+ </DriveViewConfigProvider>
70
68
  );
71
69
  }
72
70
 
@@ -91,8 +89,7 @@ export function GoogleDriveView() {
91
89
  * GoogleDriveGrid
92
90
  */
93
91
  function GoogleDriveGrid(props: ComponentProps<"div">) {
94
- const { queryData, strategy, commands, selection, meta } =
95
- useTableConfigContext<GoogleDriveNode>();
92
+ const { queryData, strategy, commands, selection, meta } = useDriveViewConfig<GoogleDriveNode>();
96
93
  const { rowCount, paginationState } = strategy;
97
94
  const { isFetching, isFetchingNextPage, fetchNextPage } = strategy.meta as InfiniteStrategyMeta;
98
95
 
@@ -107,7 +104,7 @@ function GoogleDriveGrid(props: ComponentProps<"div">) {
107
104
  <DriveGrid {...props}>
108
105
  {queryData.length > 0 ? (
109
106
  queryData.map((node) => (
110
- <DriveGridCard key={node.id} node={node} commands={commands} unoptimized />
107
+ <DriveGridCard key={node.id} node={node} commands={commands?.node} unoptimized />
111
108
  ))
112
109
  ) : (
113
110
  <DriveGridEmpty title="Geen resultaten gevonden" />
@@ -125,10 +122,10 @@ function GoogleDriveGrid(props: ComponentProps<"div">) {
125
122
  isFetchingNextPage={isFetchingNextPage}
126
123
  />
127
124
 
128
- {commands && commands.length > 0 && (
125
+ {commands?.selectedNodes && commands.selectedNodes.length > 0 && (
129
126
  <FloatingCommandMenu
130
- data={selectedData as never}
131
- commands={commands as never}
127
+ data={selectedData}
128
+ commands={commands.selectedNodes}
132
129
  meta={meta}
133
130
  state={selectedData.length > 0 ? "open" : "closed"}
134
131
  onSuccess={() => selection?.setRowSelection?.({})}
@@ -1,16 +1,12 @@
1
1
  "use client";
2
2
 
3
3
  import type { VisibilityState } from "@tanstack/react-table";
4
- import type { CommandDef } from "@tulip-systems/core/commands";
5
4
  import { FloatingCommandMenu } from "@tulip-systems/core/commands/client";
6
5
  import { type TableColumnDef, TableLayout, TableSkeleton } from "@tulip-systems/core/data-tables";
7
6
  import {
8
- createTableConfig,
9
7
  DataTable,
10
8
  type InfiniteStrategyMeta,
11
- TableConfigProvider,
12
9
  type useInfiniteStrategy,
13
- useTableConfigContext,
14
10
  } from "@tulip-systems/core/data-tables/client";
15
11
  import { type ComponentProps, useMemo } from "react";
16
12
  import {
@@ -22,6 +18,12 @@ import {
22
18
  import { DriveGridCard, DriveGridCardSkeleton } from "@/components/grid-card.client";
23
19
  import { useDriveSelectionContext } from "@/components/selection.client";
24
20
  import { useDriveViewContext } from "@/components/view.client";
21
+ import {
22
+ createDriveViewConfig,
23
+ type DriveViewCommands,
24
+ DriveViewConfigProvider,
25
+ useDriveViewConfig,
26
+ } from "@/lib/view-config.client";
25
27
  import { localDriveColumns } from "../config/columns-data";
26
28
  import { localDriveImageLoader } from "../lib/helpers";
27
29
  import type { LocalDriveNodeWithAsset } from "../lib/validators";
@@ -33,7 +35,7 @@ type LocalDriveViewProviderProps<TData extends LocalDriveNodeWithAsset = LocalDr
33
35
  queryData: TData[];
34
36
  columns?: TableColumnDef<TData>[];
35
37
  strategy: ReturnType<typeof useInfiniteStrategy>;
36
- commands?: CommandDef<TData>[];
38
+ commands?: DriveViewCommands<TData>;
37
39
  columnVisibility?: VisibilityState;
38
40
  };
39
41
 
@@ -49,22 +51,21 @@ export function LocalDriveViewProvider<
49
51
  ...props
50
52
  }: LocalDriveViewProviderProps<TData>) {
51
53
  const { meta } = useLocalDriveContext();
52
- const { selection } = useDriveSelectionContext();
53
-
54
- const config = createTableConfig<TData>({
54
+ const selectionContext = useDriveSelectionContext();
55
+ const config = createDriveViewConfig<TData>({
55
56
  queryData,
56
57
  columns,
57
58
  strategy,
58
59
  commands,
59
60
  meta,
60
61
  columnVisibility,
61
- selection,
62
+ selection: selectionContext?.selection,
62
63
  });
63
64
 
64
65
  return (
65
- <TableConfigProvider config={config}>
66
+ <DriveViewConfigProvider config={config}>
66
67
  <TableLayout {...props}>{children}</TableLayout>
67
- </TableConfigProvider>
68
+ </DriveViewConfigProvider>
68
69
  );
69
70
  }
70
71
 
@@ -79,7 +80,7 @@ export function LocalDriveView() {
79
80
 
80
81
  function LocalDriveGrid(props: ComponentProps<"div">) {
81
82
  const { queryData, strategy, commands, selection, meta } =
82
- useTableConfigContext<LocalDriveNodeWithAsset>();
83
+ useDriveViewConfig<LocalDriveNodeWithAsset>();
83
84
  const { optimistic } = useLocalDriveUploadZone();
84
85
 
85
86
  const { rowCount, paginationState } = strategy;
@@ -101,7 +102,7 @@ function LocalDriveGrid(props: ComponentProps<"div">) {
101
102
  <DriveGridCard
102
103
  key={node.id}
103
104
  node={node}
104
- commands={commands}
105
+ commands={commands?.node}
105
106
  imageLoader={localDriveImageLoader}
106
107
  />
107
108
  ))
@@ -121,10 +122,10 @@ function LocalDriveGrid(props: ComponentProps<"div">) {
121
122
  isFetchingNextPage={isFetchingNextPage}
122
123
  />
123
124
 
124
- {commands && commands.length > 0 && (
125
+ {commands?.selectedNodes && commands?.selectedNodes.length > 0 && (
125
126
  <FloatingCommandMenu
126
- data={selectedData as never}
127
- commands={commands as never}
127
+ data={selectedData}
128
+ commands={commands.selectedNodes}
128
129
  meta={meta}
129
130
  state={selectedData.length > 0 ? "open" : "closed"}
130
131
  onSuccess={() => {
@@ -0,0 +1,16 @@
1
+ import { createTableQuerySortingParser } from "@tulip-systems/core/data-tables/server";
2
+ import { asc, getTableColumns } from "drizzle-orm";
3
+ import { nodes } from "../lib/schema";
4
+
5
+ /**
6
+ * Local Drive specific sorting config
7
+ */
8
+ const localDriveTableQuerySortingConfig = getTableColumns(nodes);
9
+
10
+ /**
11
+ * Local Drive specific sorting parser
12
+ */
13
+ export const parseLocalDriveTableQuerySorting = createTableQuerySortingParser(
14
+ localDriveTableQuerySortingConfig,
15
+ { fallback: asc(nodes.createdAt) },
16
+ );
@@ -2,7 +2,6 @@ import stream from "node:stream/consumers";
2
2
  import type { TDatabaseSchema } from "@tulip-systems/core/config";
3
3
  import type { TableQueryResponse } from "@tulip-systems/core/data-tables/server";
4
4
  import {
5
- convertOrderByToQueryParams,
6
5
  convertSearchToQueryParams,
7
6
  createTableQueryResponse,
8
7
  } from "@tulip-systems/core/data-tables/server";
@@ -11,18 +10,7 @@ import { ServerError } from "@tulip-systems/core/router/server";
11
10
  import { type ObjectBodyInput, storageAssets } from "@tulip-systems/core/storage";
12
11
  import type { Storage } from "@tulip-systems/core/storage/server";
13
12
  import { addSeconds } from "date-fns";
14
- import {
15
- and,
16
- asc,
17
- desc,
18
- eq,
19
- getTableColumns,
20
- inArray,
21
- isNotNull,
22
- isNull,
23
- type SQL,
24
- sql,
25
- } from "drizzle-orm";
13
+ import { and, eq, getTableColumns, inArray, isNotNull, isNull, sql } from "drizzle-orm";
26
14
  import { after } from "next/server";
27
15
  import type { QueryResult } from "pg";
28
16
  import type {
@@ -34,6 +22,7 @@ import type {
34
22
  DriveReader,
35
23
  DriveReadonly,
36
24
  } from "../../../lib/contracts";
25
+ import { parseLocalDriveTableQuerySorting } from "../config/sorting";
37
26
  import { deviceSizes } from "./constants";
38
27
  import {
39
28
  inferLocalDriveNodeSubtype,
@@ -221,7 +210,7 @@ export class LocalDrive<TSchema extends TDatabaseSchema>
221
210
  filters,
222
211
  ...query
223
212
  }: GetLocalDriveNodesByParentIdInput): Promise<LocalDriveNode[]> {
224
- const orderBy = convertOrderByToQueryParams(query, nodes, asc(nodes.createdAt));
213
+ const orderBy = parseLocalDriveTableQuerySorting.parse(query);
225
214
  const search = convertSearchToQueryParams(query, [nodes.name]);
226
215
  const archivedFilter =
227
216
  filters.isArchived === true
@@ -247,7 +236,7 @@ export class LocalDrive<TSchema extends TDatabaseSchema>
247
236
  search,
248
237
  ),
249
238
  )
250
- .orderBy(orderBy as SQL);
239
+ .orderBy(...orderBy);
251
240
 
252
241
  return items.map(toLocalDriveNode);
253
242
  }
@@ -265,7 +254,7 @@ export class LocalDrive<TSchema extends TDatabaseSchema>
265
254
  filters,
266
255
  ...query
267
256
  }: ListLocalDriveTreeSchema): Promise<TableQueryResponse<LocalDriveNodeWithAsset>> {
268
- const orderBy = convertOrderByToQueryParams(query, nodes, desc(nodes.createdAt));
257
+ const orderBy = parseLocalDriveTableQuerySorting.parse(query);
269
258
  const search = convertSearchToQueryParams(query, [nodes.name]);
270
259
 
271
260
  const archivedFilter =
@@ -303,7 +292,7 @@ export class LocalDrive<TSchema extends TDatabaseSchema>
303
292
  .from(nodes)
304
293
  .where(where)
305
294
  .leftJoin(storageAssets, eq(nodes.assetId, storageAssets.id))
306
- .orderBy(orderBy as SQL)
295
+ .orderBy(...orderBy)
307
296
  .limit(limit)
308
297
  .offset(offset);
309
298
 
@@ -331,7 +320,7 @@ export class LocalDrive<TSchema extends TDatabaseSchema>
331
320
  filters,
332
321
  ...query
333
322
  }: ListLocalDriveFlatSchema): Promise<TableQueryResponse<LocalDriveNodeWithAsset>> {
334
- const orderBy = convertOrderByToQueryParams(query, nodes, desc(nodes.createdAt));
323
+ const orderBy = parseLocalDriveTableQuerySorting.parse(query);
335
324
  const search = convertSearchToQueryParams(query, [nodes.name]);
336
325
  const archivedFilter =
337
326
  filters.isArchived === true
@@ -363,7 +352,7 @@ export class LocalDrive<TSchema extends TDatabaseSchema>
363
352
  .from(nodes)
364
353
  .where(where)
365
354
  .leftJoin(storageAssets, eq(nodes.assetId, storageAssets.id))
366
- .orderBy(orderBy as SQL)
355
+ .orderBy(...orderBy)
367
356
  .limit(limit)
368
357
  .offset(offset);
369
358