@vendure/dashboard 3.3.8-master-202507290247 → 3.3.8-master-202507310242
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/app/routes/_authenticated/_collections/components/collection-contents-preview-table.tsx +1 -1
- package/src/app/routes/_authenticated/_collections/components/collection-filters-selector.tsx +11 -78
- package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +16 -8
- package/src/app/routes/_authenticated/_payment-methods/components/payment-eligibility-checker-selector.tsx +11 -81
- package/src/app/routes/_authenticated/_payment-methods/components/payment-handler-selector.tsx +10 -77
- package/src/app/routes/_authenticated/_promotions/components/promotion-actions-selector.tsx +12 -87
- package/src/app/routes/_authenticated/_promotions/components/promotion-conditions-selector.tsx +12 -87
- package/src/app/routes/_authenticated/_shipping-methods/components/shipping-calculator-selector.tsx +10 -80
- package/src/app/routes/_authenticated/_shipping-methods/components/shipping-eligibility-checker-selector.tsx +10 -79
- package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +8 -6
- package/src/app/routes/_authenticated/_system/components/payload-dialog.tsx +1 -1
- package/src/app/routes/_authenticated/_system/job-queue.graphql.ts +11 -0
- package/src/app/routes/_authenticated/_system/job-queue.tsx +99 -5
- package/src/lib/components/data-input/combination-mode-input.tsx +52 -0
- package/src/lib/components/data-input/configurable-operation-list-input.tsx +433 -0
- package/src/lib/components/data-input/custom-field-list-input.tsx +297 -0
- package/src/lib/components/data-input/datetime-input.tsx +5 -2
- package/src/lib/components/data-input/default-relation-input.tsx +599 -0
- package/src/lib/components/data-input/index.ts +6 -0
- package/src/lib/components/data-input/product-multi-selector.tsx +426 -0
- package/src/lib/components/data-input/relation-selector.tsx +7 -6
- package/src/lib/components/data-input/select-with-options.tsx +84 -0
- package/src/lib/components/data-input/struct-form-input.tsx +324 -0
- package/src/lib/components/shared/configurable-operation-arg-input.tsx +365 -21
- package/src/lib/components/shared/configurable-operation-input.tsx +81 -41
- package/src/lib/components/shared/configurable-operation-multi-selector.tsx +260 -0
- package/src/lib/components/shared/configurable-operation-selector.tsx +156 -0
- package/src/lib/components/shared/custom-fields-form.tsx +208 -37
- package/src/lib/components/shared/multi-select.tsx +1 -1
- package/src/lib/components/ui/form.tsx +4 -4
- package/src/lib/framework/extension-api/input-component-extensions.tsx +5 -1
- package/src/lib/framework/form-engine/form-schema-tools.spec.ts +472 -0
- package/src/lib/framework/form-engine/form-schema-tools.ts +340 -5
- package/src/lib/framework/form-engine/use-generated-form.tsx +24 -8
- package/src/lib/framework/form-engine/utils.ts +3 -9
- package/src/lib/framework/layout-engine/page-layout.tsx +11 -3
- package/src/lib/framework/page/list-page.tsx +9 -0
- package/src/lib/framework/page/use-detail-page.ts +3 -3
- package/src/lib/lib/utils.ts +26 -24
package/src/app/routes/_authenticated/_shipping-methods/components/shipping-calculator-selector.tsx
CHANGED
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
DropdownMenu,
|
|
5
|
-
DropdownMenuContent,
|
|
6
|
-
DropdownMenuItem,
|
|
7
|
-
DropdownMenuTrigger,
|
|
8
|
-
} from '@/vdb/components/ui/dropdown-menu.js';
|
|
9
|
-
import { api } from '@/vdb/graphql/api.js';
|
|
10
|
-
import {
|
|
11
|
-
configurableOperationDefFragment,
|
|
12
|
-
ConfigurableOperationDefFragment,
|
|
13
|
-
} from '@/vdb/graphql/fragments.js';
|
|
1
|
+
import { ConfigurableOperationSelector } from '@/vdb/components/shared/configurable-operation-selector.js';
|
|
2
|
+
import { configurableOperationDefFragment } from '@/vdb/graphql/fragments.js';
|
|
14
3
|
import { graphql } from '@/vdb/graphql/graphql.js';
|
|
15
|
-
import { Trans } from '@/vdb/lib/trans.js';
|
|
16
|
-
import { useQuery } from '@tanstack/react-query';
|
|
17
4
|
import { ConfigurableOperationInput as ConfigurableOperationInputType } from '@vendure/common/lib/generated-types';
|
|
18
|
-
import { Plus } from 'lucide-react';
|
|
19
5
|
|
|
20
6
|
export const shippingCalculatorsDocument = graphql(
|
|
21
7
|
`
|
|
@@ -34,70 +20,14 @@ interface ShippingCalculatorSelectorProps {
|
|
|
34
20
|
}
|
|
35
21
|
|
|
36
22
|
export function ShippingCalculatorSelector({ value, onChange }: Readonly<ShippingCalculatorSelectorProps>) {
|
|
37
|
-
const { data: calculatorsData } = useQuery({
|
|
38
|
-
queryKey: ['shippingCalculators'],
|
|
39
|
-
queryFn: () => api.query(shippingCalculatorsDocument),
|
|
40
|
-
staleTime: 1000 * 60 * 60 * 5,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const calculators = calculatorsData?.shippingCalculators;
|
|
44
|
-
|
|
45
|
-
const onCalculatorSelected = (calculator: ConfigurableOperationDefFragment) => {
|
|
46
|
-
const calculatorDef = calculators?.find(c => c.code === calculator.code);
|
|
47
|
-
if (!calculatorDef) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
onChange({
|
|
51
|
-
code: calculator.code,
|
|
52
|
-
arguments: calculatorDef.args.map(arg => ({
|
|
53
|
-
name: arg.name,
|
|
54
|
-
value: arg.defaultValue != null ? arg.defaultValue.toString() : '',
|
|
55
|
-
})),
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const onOperationValueChange = (newVal: ConfigurableOperationInputType) => {
|
|
60
|
-
onChange(newVal);
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const onOperationRemove = () => {
|
|
64
|
-
onChange(undefined);
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const calculatorDef = calculators?.find(c => c.code === value?.code);
|
|
68
|
-
|
|
69
23
|
return (
|
|
70
|
-
<
|
|
71
|
-
{value
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
/>
|
|
79
|
-
</div>
|
|
80
|
-
)}
|
|
81
|
-
<DropdownMenu>
|
|
82
|
-
{!value && (
|
|
83
|
-
<DropdownMenuTrigger asChild>
|
|
84
|
-
<Button variant="outline">
|
|
85
|
-
<Plus />
|
|
86
|
-
<Trans context="Add new promotion action">Select Shipping Calculator</Trans>
|
|
87
|
-
</Button>
|
|
88
|
-
</DropdownMenuTrigger>
|
|
89
|
-
)}
|
|
90
|
-
<DropdownMenuContent className="w-96">
|
|
91
|
-
{calculators?.map(calculator => (
|
|
92
|
-
<DropdownMenuItem
|
|
93
|
-
key={calculator.code}
|
|
94
|
-
onClick={() => onCalculatorSelected(calculator)}
|
|
95
|
-
>
|
|
96
|
-
{calculator.description}
|
|
97
|
-
</DropdownMenuItem>
|
|
98
|
-
))}
|
|
99
|
-
</DropdownMenuContent>
|
|
100
|
-
</DropdownMenu>
|
|
101
|
-
</div>
|
|
24
|
+
<ConfigurableOperationSelector
|
|
25
|
+
value={value}
|
|
26
|
+
onChange={onChange}
|
|
27
|
+
queryDocument={shippingCalculatorsDocument}
|
|
28
|
+
queryKey="shippingCalculators"
|
|
29
|
+
dataPath="shippingCalculators"
|
|
30
|
+
buttonText="Select Shipping Calculator"
|
|
31
|
+
/>
|
|
102
32
|
);
|
|
103
33
|
}
|
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
DropdownMenu,
|
|
5
|
-
DropdownMenuContent,
|
|
6
|
-
DropdownMenuItem,
|
|
7
|
-
DropdownMenuTrigger,
|
|
8
|
-
} from '@/vdb/components/ui/dropdown-menu.js';
|
|
9
|
-
import { api } from '@/vdb/graphql/api.js';
|
|
10
|
-
import {
|
|
11
|
-
configurableOperationDefFragment,
|
|
12
|
-
ConfigurableOperationDefFragment,
|
|
13
|
-
} from '@/vdb/graphql/fragments.js';
|
|
1
|
+
import { ConfigurableOperationSelector } from '@/vdb/components/shared/configurable-operation-selector.js';
|
|
2
|
+
import { configurableOperationDefFragment } from '@/vdb/graphql/fragments.js';
|
|
14
3
|
import { graphql } from '@/vdb/graphql/graphql.js';
|
|
15
|
-
import { Trans } from '@/vdb/lib/trans.js';
|
|
16
|
-
import { useQuery } from '@tanstack/react-query';
|
|
17
4
|
import { ConfigurableOperationInput as ConfigurableOperationInputType } from '@vendure/common/lib/generated-types';
|
|
18
|
-
import { Plus } from 'lucide-react';
|
|
19
5
|
|
|
20
6
|
export const shippingEligibilityCheckersDocument = graphql(
|
|
21
7
|
`
|
|
@@ -37,69 +23,14 @@ export function ShippingEligibilityCheckerSelector({
|
|
|
37
23
|
value,
|
|
38
24
|
onChange,
|
|
39
25
|
}: ShippingEligibilityCheckerSelectorProps) {
|
|
40
|
-
const { data: checkersData } = useQuery({
|
|
41
|
-
queryKey: ['shippingEligibilityCheckers'],
|
|
42
|
-
queryFn: () => api.query(shippingEligibilityCheckersDocument),
|
|
43
|
-
staleTime: 1000 * 60 * 60 * 5,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const checkers = checkersData?.shippingEligibilityCheckers;
|
|
47
|
-
|
|
48
|
-
const onCheckerSelected = (checker: ConfigurableOperationDefFragment) => {
|
|
49
|
-
const checkerDef = checkers?.find(c => c.code === checker.code);
|
|
50
|
-
if (!checkerDef) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
onChange({
|
|
54
|
-
code: checker.code,
|
|
55
|
-
arguments: checkerDef.args.map(arg => ({
|
|
56
|
-
name: arg.name,
|
|
57
|
-
value: arg.defaultValue != null ? arg.defaultValue.toString() : '',
|
|
58
|
-
})),
|
|
59
|
-
});
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const onOperationValueChange = (newVal: ConfigurableOperationInputType) => {
|
|
63
|
-
onChange(newVal);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const onOperationRemove = () => {
|
|
67
|
-
onChange(undefined);
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const checkerDef = checkers?.find(c => c.code === value?.code);
|
|
71
|
-
|
|
72
26
|
return (
|
|
73
|
-
<
|
|
74
|
-
{value
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
/>
|
|
82
|
-
</div>
|
|
83
|
-
)}
|
|
84
|
-
<DropdownMenu>
|
|
85
|
-
{!value && (
|
|
86
|
-
<DropdownMenuTrigger asChild>
|
|
87
|
-
<Button variant="outline">
|
|
88
|
-
<Plus />
|
|
89
|
-
<Trans context="Add new promotion action">
|
|
90
|
-
Select Shipping Eligibility Checker
|
|
91
|
-
</Trans>
|
|
92
|
-
</Button>
|
|
93
|
-
</DropdownMenuTrigger>
|
|
94
|
-
)}
|
|
95
|
-
<DropdownMenuContent className="w-96">
|
|
96
|
-
{checkers?.map(checker => (
|
|
97
|
-
<DropdownMenuItem key={checker.code} onClick={() => onCheckerSelected(checker)}>
|
|
98
|
-
{checker.description}
|
|
99
|
-
</DropdownMenuItem>
|
|
100
|
-
))}
|
|
101
|
-
</DropdownMenuContent>
|
|
102
|
-
</DropdownMenu>
|
|
103
|
-
</div>
|
|
27
|
+
<ConfigurableOperationSelector
|
|
28
|
+
value={value}
|
|
29
|
+
onChange={onChange}
|
|
30
|
+
queryDocument={shippingEligibilityCheckersDocument}
|
|
31
|
+
queryKey="shippingEligibilityCheckers"
|
|
32
|
+
dataPath="shippingEligibilityCheckers"
|
|
33
|
+
buttonText="Select Shipping Eligibility Checker"
|
|
34
|
+
/>
|
|
104
35
|
);
|
|
105
36
|
}
|
|
@@ -130,12 +130,14 @@ function ShippingMethodDetailPage() {
|
|
|
130
130
|
render={({ field }) => <Input {...field} />}
|
|
131
131
|
/>
|
|
132
132
|
</DetailFormGrid>
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
<div className="mb-6">
|
|
134
|
+
<TranslatableFormFieldWrapper
|
|
135
|
+
control={form.control}
|
|
136
|
+
name="description"
|
|
137
|
+
label={<Trans>Description</Trans>}
|
|
138
|
+
render={({ field }) => <Textarea {...field} />}
|
|
139
|
+
/>
|
|
140
|
+
</div>
|
|
139
141
|
<DetailFormGrid>
|
|
140
142
|
<FormFieldWrapper
|
|
141
143
|
control={form.control}
|
|
@@ -26,7 +26,7 @@ export function PayloadDialog({ payload, trigger, title, description }: Readonly
|
|
|
26
26
|
<DialogDescription>{description}</DialogDescription>
|
|
27
27
|
</DialogHeader>
|
|
28
28
|
<ScrollArea className="max-h-[600px]">
|
|
29
|
-
<JsonEditor viewOnly data={payload} collapse />
|
|
29
|
+
<JsonEditor viewOnly data={payload} collapse={1} rootFontSize={12} />
|
|
30
30
|
</ScrollArea>
|
|
31
31
|
</DialogContent>
|
|
32
32
|
</Dialog>
|
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
import { Badge } from '@/vdb/components/ui/badge.js';
|
|
2
2
|
import { Button } from '@/vdb/components/ui/button.js';
|
|
3
|
+
import {
|
|
4
|
+
DropdownMenu,
|
|
5
|
+
DropdownMenuContent,
|
|
6
|
+
DropdownMenuItem,
|
|
7
|
+
DropdownMenuTrigger,
|
|
8
|
+
} from '@/vdb/components/ui/dropdown-menu.js';
|
|
9
|
+
import { PageActionBarRight } from '@/vdb/framework/layout-engine/page-layout.js';
|
|
3
10
|
import { ListPage } from '@/vdb/framework/page/list-page.js';
|
|
4
11
|
import { api } from '@/vdb/graphql/api.js';
|
|
5
12
|
import { Trans } from '@/vdb/lib/trans.js';
|
|
13
|
+
import { useMutation } from '@tanstack/react-query';
|
|
6
14
|
import { createFileRoute } from '@tanstack/react-router';
|
|
7
15
|
import { formatRelative } from 'date-fns';
|
|
8
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
Ban,
|
|
18
|
+
CheckCircle2Icon,
|
|
19
|
+
ChevronDown,
|
|
20
|
+
CircleXIcon,
|
|
21
|
+
ClockIcon,
|
|
22
|
+
LoaderIcon,
|
|
23
|
+
MoreVertical,
|
|
24
|
+
RefreshCw,
|
|
25
|
+
RotateCcw,
|
|
26
|
+
} from 'lucide-react';
|
|
27
|
+
import { useEffect, useRef, useState } from 'react';
|
|
9
28
|
import { PayloadDialog } from './components/payload-dialog.js';
|
|
10
|
-
import { jobListDocument, jobQueueListDocument } from './job-queue.graphql.js';
|
|
29
|
+
import { cancelJobDocument, jobListDocument, jobQueueListDocument } from './job-queue.graphql.js';
|
|
11
30
|
|
|
12
31
|
export const Route = createFileRoute('/_authenticated/_system/job-queue')({
|
|
13
32
|
component: JobQueuePage,
|
|
@@ -47,7 +66,30 @@ const STATES = [
|
|
|
47
66
|
},
|
|
48
67
|
];
|
|
49
68
|
|
|
69
|
+
const REFRESH_INTERVALS = [
|
|
70
|
+
{ label: <Trans>Off</Trans>, value: 0 },
|
|
71
|
+
{ label: <Trans>Every 5 seconds</Trans>, value: 5000 },
|
|
72
|
+
{ label: <Trans>Every 10 seconds</Trans>, value: 10000 },
|
|
73
|
+
{ label: <Trans>Every 30 seconds</Trans>, value: 30000 },
|
|
74
|
+
{ label: <Trans>Every 60 seconds</Trans>, value: 60000 },
|
|
75
|
+
];
|
|
76
|
+
|
|
50
77
|
function JobQueuePage() {
|
|
78
|
+
const refreshRef = useRef<() => void>(() => {});
|
|
79
|
+
const [refreshInterval, setRefreshInterval] = useState(10000);
|
|
80
|
+
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (refreshInterval === 0) return;
|
|
83
|
+
|
|
84
|
+
const interval = setInterval(() => {
|
|
85
|
+
refreshRef.current();
|
|
86
|
+
}, refreshInterval);
|
|
87
|
+
|
|
88
|
+
return () => clearInterval(interval);
|
|
89
|
+
}, [refreshInterval]);
|
|
90
|
+
|
|
91
|
+
const currentInterval = REFRESH_INTERVALS.find(i => i.value === refreshInterval);
|
|
92
|
+
|
|
51
93
|
return (
|
|
52
94
|
<ListPage
|
|
53
95
|
pageId="job-queue-list"
|
|
@@ -105,9 +147,14 @@ function JobQueuePage() {
|
|
|
105
147
|
},
|
|
106
148
|
state: {
|
|
107
149
|
header: 'State',
|
|
108
|
-
cell: ({ row }) => {
|
|
150
|
+
cell: ({ row, table }) => {
|
|
151
|
+
const cancelJobMutation = useMutation({
|
|
152
|
+
mutationFn: (jobId: string) => api.mutate(cancelJobDocument, { jobId }),
|
|
153
|
+
onSuccess: () => {
|
|
154
|
+
refreshRef.current();
|
|
155
|
+
},
|
|
156
|
+
});
|
|
109
157
|
const state = STATES.find(s => s.value === row.original.state);
|
|
110
|
-
|
|
111
158
|
return (
|
|
112
159
|
<Badge
|
|
113
160
|
variant={
|
|
@@ -122,6 +169,27 @@ function JobQueuePage() {
|
|
|
122
169
|
>
|
|
123
170
|
{state && <state.icon />}
|
|
124
171
|
{row.original.state}
|
|
172
|
+
{row.original.state === 'RUNNING' ? (
|
|
173
|
+
<div className="flex items-center gap-2">
|
|
174
|
+
<DropdownMenu>
|
|
175
|
+
<DropdownMenuTrigger asChild>
|
|
176
|
+
<Button variant="ghost" size="sm" className="h-6 w-6 p-0">
|
|
177
|
+
<MoreVertical className="h-4 w-4" />
|
|
178
|
+
</Button>
|
|
179
|
+
</DropdownMenuTrigger>
|
|
180
|
+
<DropdownMenuContent align="end">
|
|
181
|
+
<DropdownMenuItem
|
|
182
|
+
onClick={() => cancelJobMutation.mutate(row.original.id)}
|
|
183
|
+
disabled={cancelJobMutation.isPending}
|
|
184
|
+
className="text-destructive focus:text-destructive"
|
|
185
|
+
>
|
|
186
|
+
<Ban className="mr-2 h-4 w-4" />
|
|
187
|
+
<Trans>Cancel Job</Trans>
|
|
188
|
+
</DropdownMenuItem>
|
|
189
|
+
</DropdownMenuContent>
|
|
190
|
+
</DropdownMenu>
|
|
191
|
+
</div>
|
|
192
|
+
) : null}
|
|
125
193
|
</Badge>
|
|
126
194
|
);
|
|
127
195
|
},
|
|
@@ -159,6 +227,32 @@ function JobQueuePage() {
|
|
|
159
227
|
options: STATES,
|
|
160
228
|
},
|
|
161
229
|
}}
|
|
162
|
-
|
|
230
|
+
registerRefresher={refresher => {
|
|
231
|
+
refreshRef.current = refresher;
|
|
232
|
+
}}
|
|
233
|
+
>
|
|
234
|
+
<PageActionBarRight>
|
|
235
|
+
<DropdownMenu>
|
|
236
|
+
<DropdownMenuTrigger asChild>
|
|
237
|
+
<Button variant="outline" size="sm" className="gap-2">
|
|
238
|
+
<RefreshCw className="h-4 w-4" />
|
|
239
|
+
<span>Auto refresh: {currentInterval?.label}</span>
|
|
240
|
+
<ChevronDown className="h-4 w-4" />
|
|
241
|
+
</Button>
|
|
242
|
+
</DropdownMenuTrigger>
|
|
243
|
+
<DropdownMenuContent align="end">
|
|
244
|
+
{REFRESH_INTERVALS.map(interval => (
|
|
245
|
+
<DropdownMenuItem
|
|
246
|
+
key={interval.value}
|
|
247
|
+
onClick={() => setRefreshInterval(interval.value)}
|
|
248
|
+
className={refreshInterval === interval.value ? 'bg-accent' : ''}
|
|
249
|
+
>
|
|
250
|
+
{interval.label}
|
|
251
|
+
</DropdownMenuItem>
|
|
252
|
+
))}
|
|
253
|
+
</DropdownMenuContent>
|
|
254
|
+
</DropdownMenu>
|
|
255
|
+
</PageActionBarRight>
|
|
256
|
+
</ListPage>
|
|
163
257
|
);
|
|
164
258
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { DataInputComponent } from '@/vdb/framework/component-registry/component-registry.js';
|
|
2
|
+
import { Trans } from '@/vdb/lib/trans.js';
|
|
3
|
+
|
|
4
|
+
export const CombinationModeInput: DataInputComponent = ({ value, onChange, position, ...props }) => {
|
|
5
|
+
const booleanValue = value === 'true' || value === true;
|
|
6
|
+
|
|
7
|
+
// Only show for items after the first one
|
|
8
|
+
const selectable = position !== undefined && position > 0;
|
|
9
|
+
|
|
10
|
+
const setCombinationModeAnd = () => {
|
|
11
|
+
onChange(true);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const setCombinationModeOr = () => {
|
|
15
|
+
onChange(false);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
if (!selectable) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className="flex items-center justify-center -mt-4 -mb-4">
|
|
24
|
+
<div className="bg-muted border px-3 py-1.5 rounded-full flex gap-1.5 text-xs shadow-sm">
|
|
25
|
+
<button
|
|
26
|
+
type="button"
|
|
27
|
+
className={`px-2 py-0.5 rounded-full transition-colors ${
|
|
28
|
+
booleanValue
|
|
29
|
+
? 'bg-primary text-background'
|
|
30
|
+
: 'text-muted-foreground hover:bg-muted-foreground/10'
|
|
31
|
+
}`}
|
|
32
|
+
onClick={setCombinationModeAnd}
|
|
33
|
+
{...props}
|
|
34
|
+
>
|
|
35
|
+
<Trans>AND</Trans>
|
|
36
|
+
</button>
|
|
37
|
+
<button
|
|
38
|
+
type="button"
|
|
39
|
+
className={`px-2 py-0.5 rounded-full transition-colors ${
|
|
40
|
+
!booleanValue
|
|
41
|
+
? 'bg-primary text-background'
|
|
42
|
+
: 'text-muted-foreground hover:bg-muted-foreground/10'
|
|
43
|
+
}`}
|
|
44
|
+
onClick={setCombinationModeOr}
|
|
45
|
+
{...props}
|
|
46
|
+
>
|
|
47
|
+
<Trans>OR</Trans>
|
|
48
|
+
</button>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
};
|