@vendure/dashboard 3.4.3-master-202509250229 → 3.5.0-minor-202509261210
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/plugin/api/api-extensions.js +11 -14
- package/dist/plugin/api/metrics.resolver.d.ts +2 -2
- package/dist/plugin/api/metrics.resolver.js +2 -2
- package/dist/plugin/config/metrics-strategies.d.ts +9 -9
- package/dist/plugin/config/metrics-strategies.js +6 -6
- package/dist/plugin/constants.d.ts +2 -0
- package/dist/plugin/constants.js +3 -1
- package/dist/plugin/dashboard.plugin.js +13 -0
- package/dist/plugin/service/metrics.service.d.ts +3 -3
- package/dist/plugin/service/metrics.service.js +37 -53
- package/dist/plugin/types.d.ts +9 -12
- package/dist/plugin/types.js +7 -11
- package/dist/vite/utils/compiler.js +2 -0
- package/dist/vite/vite-plugin-vendure-dashboard.js +2 -2
- package/package.json +4 -4
- package/src/app/routes/_authenticated/_collections/collections.tsx +7 -2
- package/src/app/routes/_authenticated/_collections/collections_.$id.tsx +15 -2
- package/src/app/routes/_authenticated/_facets/facets_.$id.tsx +14 -2
- package/src/app/routes/_authenticated/_product-variants/product-variants.graphql.ts +10 -0
- package/src/app/routes/_authenticated/_products/components/product-option-group-badge.tsx +19 -0
- package/src/app/routes/_authenticated/_products/components/product-options-table.tsx +111 -0
- package/src/app/routes/_authenticated/_products/product-option-groups.graphql.ts +103 -0
- package/src/app/routes/_authenticated/_products/products.graphql.ts +13 -1
- package/src/app/routes/_authenticated/_products/products.tsx +27 -3
- package/src/app/routes/_authenticated/_products/products_.$id.tsx +26 -9
- package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$id.tsx +181 -0
- package/src/app/routes/_authenticated/_products/products_.$productId.option-groups.$productOptionGroupId.options_.$id.tsx +208 -0
- package/src/app/routes/_authenticated/_zones/components/zone-countries-sheet.tsx +4 -1
- package/src/app/routes/_authenticated/index.tsx +41 -24
- package/src/lib/components/data-display/json.tsx +16 -1
- package/src/lib/components/data-input/index.ts +3 -0
- package/src/lib/components/data-input/slug-input.tsx +296 -0
- package/src/lib/components/data-table/add-filter-menu.tsx +13 -6
- package/src/lib/components/data-table/data-table-bulk-action-item.tsx +38 -1
- package/src/lib/components/data-table/data-table-context.tsx +91 -0
- package/src/lib/components/data-table/data-table-filter-badge.tsx +9 -5
- package/src/lib/components/data-table/data-table-view-options.tsx +17 -8
- package/src/lib/components/data-table/data-table.tsx +146 -94
- package/src/lib/components/data-table/global-views-bar.tsx +97 -0
- package/src/lib/components/data-table/global-views-sheet.tsx +11 -0
- package/src/lib/components/data-table/manage-global-views-button.tsx +26 -0
- package/src/lib/components/data-table/my-views-button.tsx +47 -0
- package/src/lib/components/data-table/refresh-button.tsx +12 -3
- package/src/lib/components/data-table/save-view-button.tsx +45 -0
- package/src/lib/components/data-table/save-view-dialog.tsx +113 -0
- package/src/lib/components/data-table/use-generated-columns.tsx +3 -1
- package/src/lib/components/data-table/user-views-sheet.tsx +11 -0
- package/src/lib/components/data-table/views-sheet.tsx +297 -0
- package/src/lib/components/date-range-picker.tsx +184 -0
- package/src/lib/components/shared/paginated-list-data-table.tsx +59 -32
- package/src/lib/components/ui/button.tsx +1 -1
- package/src/lib/framework/dashboard-widget/latest-orders-widget/index.tsx +29 -2
- package/src/lib/framework/dashboard-widget/metrics-widget/index.tsx +10 -7
- package/src/lib/framework/dashboard-widget/metrics-widget/metrics-widget.graphql.ts +9 -3
- package/src/lib/framework/dashboard-widget/orders-summary/index.tsx +19 -75
- package/src/lib/framework/dashboard-widget/widget-filters-context.tsx +33 -0
- package/src/lib/framework/document-introspection/add-custom-fields.spec.ts +319 -9
- package/src/lib/framework/document-introspection/add-custom-fields.ts +60 -31
- package/src/lib/framework/document-introspection/get-document-structure.spec.ts +1 -159
- package/src/lib/framework/document-introspection/include-only-selected-list-fields.spec.ts +1840 -0
- package/src/lib/framework/document-introspection/include-only-selected-list-fields.ts +940 -0
- package/src/lib/framework/document-introspection/testing-utils.ts +161 -0
- package/src/lib/framework/extension-api/display-component-extensions.tsx +2 -0
- package/src/lib/framework/extension-api/types/data-table.ts +62 -4
- package/src/lib/framework/extension-api/types/navigation.ts +16 -0
- package/src/lib/framework/form-engine/utils.ts +34 -0
- package/src/lib/framework/page/list-page.tsx +289 -4
- package/src/lib/framework/page/use-extended-router.tsx +59 -17
- package/src/lib/graphql/api.ts +4 -2
- package/src/lib/graphql/graphql-env.d.ts +13 -10
- package/src/lib/hooks/use-extended-list-query.ts +5 -0
- package/src/lib/hooks/use-saved-views.ts +230 -0
- package/src/lib/index.ts +15 -0
- package/src/lib/types/saved-views.ts +39 -0
- package/src/lib/utils/saved-views-utils.ts +40 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { ChevronDown } from 'lucide-react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useSavedViews } from '../../hooks/use-saved-views.js';
|
|
4
|
+
import { Trans } from '../../lib/trans.js';
|
|
5
|
+
import { SavedView } from '../../types/saved-views.js';
|
|
6
|
+
import { findMatchingSavedView } from '../../utils/saved-views-utils.js';
|
|
7
|
+
import { PermissionGuard } from '../shared/permission-guard.js';
|
|
8
|
+
import { Button } from '../ui/button.js';
|
|
9
|
+
import {
|
|
10
|
+
DropdownMenu,
|
|
11
|
+
DropdownMenuContent,
|
|
12
|
+
DropdownMenuItem,
|
|
13
|
+
DropdownMenuTrigger,
|
|
14
|
+
} from '../ui/dropdown-menu.js';
|
|
15
|
+
import { useDataTableContext } from './data-table-context.js';
|
|
16
|
+
import { ManageGlobalViewsButton } from './manage-global-views-button.js';
|
|
17
|
+
|
|
18
|
+
export const GlobalViewsBar: React.FC = () => {
|
|
19
|
+
const { globalViews, canManageGlobalViews } = useSavedViews();
|
|
20
|
+
const { columnFilters, searchTerm, handleApplyView } = useDataTableContext();
|
|
21
|
+
|
|
22
|
+
if (globalViews.length === 0) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const sortedViews = [...globalViews].sort(
|
|
27
|
+
(a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(),
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const handleViewClick = (view: SavedView) => {
|
|
31
|
+
handleApplyView(view.filters, view.searchTerm);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const isViewActive = (view: SavedView) => {
|
|
35
|
+
return findMatchingSavedView(columnFilters, searchTerm, [view]) !== undefined;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
if (sortedViews.length <= 3) {
|
|
39
|
+
// Show all views as buttons
|
|
40
|
+
return (
|
|
41
|
+
<div className="flex items-center gap-1">
|
|
42
|
+
{sortedViews.map(view => (
|
|
43
|
+
<Button
|
|
44
|
+
key={view.id}
|
|
45
|
+
variant={isViewActive(view) ? 'default' : 'outline'}
|
|
46
|
+
size="sm"
|
|
47
|
+
onClick={() => handleViewClick(view)}
|
|
48
|
+
>
|
|
49
|
+
{view.name}
|
|
50
|
+
</Button>
|
|
51
|
+
))}
|
|
52
|
+
{canManageGlobalViews && <ManageGlobalViewsButton />}
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Show first 3 as buttons, rest in dropdown
|
|
58
|
+
const visibleViews = sortedViews.slice(0, 3);
|
|
59
|
+
const dropdownViews = sortedViews.slice(3);
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div className="flex items-center gap-1">
|
|
63
|
+
{visibleViews.map(view => (
|
|
64
|
+
<Button
|
|
65
|
+
key={view.id}
|
|
66
|
+
variant={isViewActive(view) ? 'default' : 'outline'}
|
|
67
|
+
size="sm"
|
|
68
|
+
onClick={() => handleViewClick(view)}
|
|
69
|
+
>
|
|
70
|
+
{view.name}
|
|
71
|
+
</Button>
|
|
72
|
+
))}
|
|
73
|
+
<DropdownMenu>
|
|
74
|
+
<DropdownMenuTrigger asChild>
|
|
75
|
+
<Button variant="outline" size="sm">
|
|
76
|
+
<Trans>More views</Trans>
|
|
77
|
+
<ChevronDown className="h-3 w-3" />
|
|
78
|
+
</Button>
|
|
79
|
+
</DropdownMenuTrigger>
|
|
80
|
+
<DropdownMenuContent align="start">
|
|
81
|
+
{dropdownViews.map(view => (
|
|
82
|
+
<DropdownMenuItem
|
|
83
|
+
key={view.id}
|
|
84
|
+
onClick={() => handleViewClick(view)}
|
|
85
|
+
className={isViewActive(view) ? 'bg-primary' : ''}
|
|
86
|
+
>
|
|
87
|
+
{view.name}
|
|
88
|
+
</DropdownMenuItem>
|
|
89
|
+
))}
|
|
90
|
+
</DropdownMenuContent>
|
|
91
|
+
</DropdownMenu>
|
|
92
|
+
<PermissionGuard requires={['WriteDashboardGlobalViews']}>
|
|
93
|
+
{canManageGlobalViews && <ManageGlobalViewsButton />}
|
|
94
|
+
</PermissionGuard>
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ViewsSheet } from './views-sheet.js';
|
|
3
|
+
|
|
4
|
+
interface GlobalViewsSheetProps {
|
|
5
|
+
open: boolean;
|
|
6
|
+
onOpenChange: (open: boolean) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const GlobalViewsSheet: React.FC<GlobalViewsSheetProps> = ({ open, onOpenChange }) => {
|
|
10
|
+
return <ViewsSheet open={open} onOpenChange={onOpenChange} type="global" />;
|
|
11
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Settings } from 'lucide-react';
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import { Button } from '../ui/button.js';
|
|
4
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip.js';
|
|
5
|
+
import { Trans } from '@/vdb/lib/trans.js';
|
|
6
|
+
import { GlobalViewsSheet } from './global-views-sheet.js';
|
|
7
|
+
|
|
8
|
+
export const ManageGlobalViewsButton: React.FC = () => {
|
|
9
|
+
const [sheetOpen, setSheetOpen] = useState(false);
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<>
|
|
13
|
+
<Tooltip>
|
|
14
|
+
<TooltipTrigger asChild>
|
|
15
|
+
<Button variant="outline" size="icon-sm" onClick={() => setSheetOpen(true)}>
|
|
16
|
+
<Settings />
|
|
17
|
+
</Button>
|
|
18
|
+
</TooltipTrigger>
|
|
19
|
+
<TooltipContent>
|
|
20
|
+
<Trans>Manage global views</Trans>
|
|
21
|
+
</TooltipContent>
|
|
22
|
+
</Tooltip>
|
|
23
|
+
<GlobalViewsSheet open={sheetOpen} onOpenChange={setSheetOpen} />
|
|
24
|
+
</>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Bookmark } from 'lucide-react';
|
|
2
|
+
import React, { useState, useMemo } from 'react';
|
|
3
|
+
import { Button } from '../ui/button.js';
|
|
4
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip.js';
|
|
5
|
+
import { Trans } from '@/vdb/lib/trans.js';
|
|
6
|
+
import { UserViewsSheet } from './user-views-sheet.js';
|
|
7
|
+
import { useSavedViews } from '../../hooks/use-saved-views.js';
|
|
8
|
+
import { findMatchingSavedView } from '../../utils/saved-views-utils.js';
|
|
9
|
+
import { useDataTableContext } from './data-table-context.js';
|
|
10
|
+
|
|
11
|
+
export const MyViewsButton: React.FC = () => {
|
|
12
|
+
const [sheetOpen, setSheetOpen] = useState(false);
|
|
13
|
+
const { userViews } = useSavedViews();
|
|
14
|
+
const { columnFilters, searchTerm, handleApplyView } = useDataTableContext();
|
|
15
|
+
|
|
16
|
+
// Find the active view using centralized utility
|
|
17
|
+
const activeView = useMemo(() => {
|
|
18
|
+
return findMatchingSavedView(columnFilters, searchTerm, userViews);
|
|
19
|
+
}, [userViews, columnFilters, searchTerm]);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
<div className="flex items-center gap-2">
|
|
24
|
+
<Tooltip>
|
|
25
|
+
<TooltipTrigger asChild>
|
|
26
|
+
<Button
|
|
27
|
+
variant={activeView ? "default" : "outline"}
|
|
28
|
+
size="icon"
|
|
29
|
+
onClick={() => setSheetOpen(true)}
|
|
30
|
+
>
|
|
31
|
+
<Bookmark />
|
|
32
|
+
</Button>
|
|
33
|
+
</TooltipTrigger>
|
|
34
|
+
<TooltipContent>
|
|
35
|
+
<Trans>My saved views</Trans>
|
|
36
|
+
</TooltipContent>
|
|
37
|
+
</Tooltip>
|
|
38
|
+
{activeView && (
|
|
39
|
+
<span className="text-sm text-muted-foreground">
|
|
40
|
+
{activeView.name}
|
|
41
|
+
</span>
|
|
42
|
+
)}
|
|
43
|
+
</div>
|
|
44
|
+
<UserViewsSheet open={sheetOpen} onOpenChange={setSheetOpen} />
|
|
45
|
+
</>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Button } from '@/vdb/components/ui/button.js';
|
|
2
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from '@/vdb/components/ui/tooltip.js';
|
|
3
|
+
import { Trans } from '@/vdb/lib/trans.js';
|
|
2
4
|
import { RefreshCw } from 'lucide-react';
|
|
3
5
|
import { useEffect, useState } from 'react';
|
|
4
6
|
|
|
@@ -33,8 +35,15 @@ export function RefreshButton({
|
|
|
33
35
|
};
|
|
34
36
|
|
|
35
37
|
return (
|
|
36
|
-
<
|
|
37
|
-
<
|
|
38
|
-
|
|
38
|
+
<Tooltip>
|
|
39
|
+
<TooltipTrigger asChild>
|
|
40
|
+
<Button variant="outline" size="sm" onClick={handleClick} disabled={delayedLoading}>
|
|
41
|
+
<RefreshCw className={delayedLoading ? 'animate-rotate' : ''} />
|
|
42
|
+
</Button>
|
|
43
|
+
</TooltipTrigger>
|
|
44
|
+
<TooltipContent>
|
|
45
|
+
<Trans>Refresh data</Trans>
|
|
46
|
+
</TooltipContent>
|
|
47
|
+
</Tooltip>
|
|
39
48
|
);
|
|
40
49
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { BookmarkPlus } from 'lucide-react';
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import { Button } from '../ui/button.js';
|
|
4
|
+
import { SaveViewDialog } from './save-view-dialog.js';
|
|
5
|
+
import { useSavedViews } from '../../hooks/use-saved-views.js';
|
|
6
|
+
import { isMatchingSavedView } from '../../utils/saved-views-utils.js';
|
|
7
|
+
import { useDataTableContext } from './data-table-context.js';
|
|
8
|
+
|
|
9
|
+
interface SaveViewButtonProps {
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const SaveViewButton: React.FC<SaveViewButtonProps> = ({ disabled }) => {
|
|
14
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
|
15
|
+
const { userViews, globalViews } = useSavedViews();
|
|
16
|
+
const { columnFilters, searchTerm } = useDataTableContext();
|
|
17
|
+
|
|
18
|
+
const hasFilters = columnFilters.length > 0 || (searchTerm && searchTerm.length > 0);
|
|
19
|
+
const matchesExistingView = isMatchingSavedView(columnFilters, searchTerm || '', userViews, globalViews);
|
|
20
|
+
|
|
21
|
+
// Don't show the button if there are no filters or if filters match an existing saved view
|
|
22
|
+
if (!hasFilters || matchesExistingView) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<>
|
|
28
|
+
<Button
|
|
29
|
+
variant="outline"
|
|
30
|
+
size="sm"
|
|
31
|
+
onClick={() => setDialogOpen(true)}
|
|
32
|
+
disabled={disabled}
|
|
33
|
+
>
|
|
34
|
+
<BookmarkPlus className="h-4 w-4 mr-1" />
|
|
35
|
+
Save View
|
|
36
|
+
</Button>
|
|
37
|
+
<SaveViewDialog
|
|
38
|
+
open={dialogOpen}
|
|
39
|
+
onOpenChange={setDialogOpen}
|
|
40
|
+
filters={columnFilters}
|
|
41
|
+
searchTerm={searchTerm}
|
|
42
|
+
/>
|
|
43
|
+
</>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { ColumnFiltersState } from '@tanstack/react-table';
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import { useSavedViews } from '../../hooks/use-saved-views.js';
|
|
4
|
+
import { Button } from '../ui/button.js';
|
|
5
|
+
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '../ui/dialog.js';
|
|
6
|
+
import { Input } from '../ui/input.js';
|
|
7
|
+
import { Label } from '../ui/label.js';
|
|
8
|
+
import { RadioGroup, RadioGroupItem } from '../ui/radio-group.js';
|
|
9
|
+
import { toast } from 'sonner';
|
|
10
|
+
|
|
11
|
+
interface SaveViewDialogProps {
|
|
12
|
+
open: boolean;
|
|
13
|
+
onOpenChange: (open: boolean) => void;
|
|
14
|
+
filters: ColumnFiltersState;
|
|
15
|
+
searchTerm?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const SaveViewDialog: React.FC<SaveViewDialogProps> = ({
|
|
19
|
+
open,
|
|
20
|
+
onOpenChange,
|
|
21
|
+
filters,
|
|
22
|
+
searchTerm,
|
|
23
|
+
}) => {
|
|
24
|
+
const [name, setName] = useState('');
|
|
25
|
+
const [scope, setScope] = useState<'user' | 'global'>('user');
|
|
26
|
+
const [saving, setSaving] = useState(false);
|
|
27
|
+
const { saveView, userViews, globalViews, canManageGlobalViews } = useSavedViews();
|
|
28
|
+
|
|
29
|
+
const handleSave = async () => {
|
|
30
|
+
if (!name.trim()) {
|
|
31
|
+
toast.error('Please enter a name for the view');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Check for duplicate names
|
|
36
|
+
const existingViews = scope === 'user' ? userViews : globalViews;
|
|
37
|
+
if (existingViews.some(v => v.name === name.trim())) {
|
|
38
|
+
toast.error(`A ${scope} view with this name already exists`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setSaving(true);
|
|
43
|
+
try {
|
|
44
|
+
await saveView({
|
|
45
|
+
name: name.trim(),
|
|
46
|
+
scope,
|
|
47
|
+
filters,
|
|
48
|
+
searchTerm,
|
|
49
|
+
});
|
|
50
|
+
toast.success(`View "${name}" saved successfully`);
|
|
51
|
+
onOpenChange(false);
|
|
52
|
+
setName('');
|
|
53
|
+
setScope('user');
|
|
54
|
+
} catch (error) {
|
|
55
|
+
toast.error('Failed to save view');
|
|
56
|
+
console.error('Failed to save view:', error);
|
|
57
|
+
} finally {
|
|
58
|
+
setSaving(false);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
64
|
+
<DialogContent>
|
|
65
|
+
<DialogHeader>
|
|
66
|
+
<DialogTitle>Save Current View</DialogTitle>
|
|
67
|
+
<DialogDescription>
|
|
68
|
+
Save the current filters and search term as a reusable view.
|
|
69
|
+
</DialogDescription>
|
|
70
|
+
</DialogHeader>
|
|
71
|
+
<div className="space-y-4 py-4">
|
|
72
|
+
<div className="space-y-2">
|
|
73
|
+
<Label htmlFor="view-name">View Name</Label>
|
|
74
|
+
<Input
|
|
75
|
+
id="view-name"
|
|
76
|
+
value={name}
|
|
77
|
+
onChange={e => setName(e.target.value)}
|
|
78
|
+
placeholder="Enter a name for this view"
|
|
79
|
+
autoFocus
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
82
|
+
{canManageGlobalViews && (
|
|
83
|
+
<div className="space-y-2">
|
|
84
|
+
<Label>View Scope</Label>
|
|
85
|
+
<RadioGroup value={scope} onValueChange={value => setScope(value as 'user' | 'global')}>
|
|
86
|
+
<div className="flex items-center space-x-2">
|
|
87
|
+
<RadioGroupItem value="user" id="scope-user" />
|
|
88
|
+
<Label htmlFor="scope-user" className="font-normal">
|
|
89
|
+
Personal View (only visible to you)
|
|
90
|
+
</Label>
|
|
91
|
+
</div>
|
|
92
|
+
<div className="flex items-center space-x-2">
|
|
93
|
+
<RadioGroupItem value="global" id="scope-global" />
|
|
94
|
+
<Label htmlFor="scope-global" className="font-normal">
|
|
95
|
+
Global View (visible to all users)
|
|
96
|
+
</Label>
|
|
97
|
+
</div>
|
|
98
|
+
</RadioGroup>
|
|
99
|
+
</div>
|
|
100
|
+
)}
|
|
101
|
+
</div>
|
|
102
|
+
<DialogFooter>
|
|
103
|
+
<Button variant="outline" onClick={() => onOpenChange(false)} disabled={saving}>
|
|
104
|
+
Cancel
|
|
105
|
+
</Button>
|
|
106
|
+
<Button onClick={handleSave} disabled={saving || !name.trim()}>
|
|
107
|
+
{saving ? 'Saving...' : 'Save View'}
|
|
108
|
+
</Button>
|
|
109
|
+
</DialogFooter>
|
|
110
|
+
</DialogContent>
|
|
111
|
+
</Dialog>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
@@ -136,7 +136,7 @@ export function useGeneratedColumns<T extends TypedDocumentNode<any, any>>({
|
|
|
136
136
|
return <DisplayComponent id="vendure:asset" value={value} />;
|
|
137
137
|
}
|
|
138
138
|
if (value !== null && typeof value === 'object') {
|
|
139
|
-
return
|
|
139
|
+
return <DisplayComponent id="vendure:json" value={value} />;
|
|
140
140
|
}
|
|
141
141
|
return value;
|
|
142
142
|
},
|
|
@@ -196,6 +196,7 @@ export function useGeneratedColumns<T extends TypedDocumentNode<any, any>>({
|
|
|
196
196
|
/>
|
|
197
197
|
),
|
|
198
198
|
enableColumnFilter: false,
|
|
199
|
+
enableHiding: false,
|
|
199
200
|
cell: ({ row }) => {
|
|
200
201
|
return (
|
|
201
202
|
<Checkbox
|
|
@@ -224,6 +225,7 @@ function getRowActions(
|
|
|
224
225
|
accessorKey: 'actions',
|
|
225
226
|
header: () => <Trans>Actions</Trans>,
|
|
226
227
|
enableColumnFilter: false,
|
|
228
|
+
enableHiding: false,
|
|
227
229
|
cell: ({ row, table }) => {
|
|
228
230
|
return (
|
|
229
231
|
<DropdownMenu>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ViewsSheet } from './views-sheet.js';
|
|
3
|
+
|
|
4
|
+
interface UserViewsSheetProps {
|
|
5
|
+
open: boolean;
|
|
6
|
+
onOpenChange: (open: boolean) => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const UserViewsSheet: React.FC<UserViewsSheetProps> = ({ open, onOpenChange }) => {
|
|
10
|
+
return <ViewsSheet open={open} onOpenChange={onOpenChange} type="user" />;
|
|
11
|
+
};
|