@nocobase/portal-template-default 1.0.4 → 1.0.6
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/README.MD +77 -0
- package/package.json +23 -17
- package/registry/nocobase-acl/demo/prompt-generator.tsx +6 -39
- package/registry/nocobase-acl/demo/role-switcher-prompt-generator.tsx +6 -42
- package/registry/nocobase-ai/demo/page-context-prompt-generator.tsx +1 -1
- package/registry/nocobase-ai/demo/prompt-card.tsx +7 -28
- package/registry/nocobase-ai/demo/prompt-generator.tsx +9 -30
- package/registry/nocobase-ai/demo/shortcut.tsx +1 -1
- package/registry/nocobase-ai/demo/tool-cards.tsx +10 -30
- package/registry/nocobase-auth-cas/README.md +6 -0
- package/registry/nocobase-auth-cas/cas-sign-in-button.tsx +41 -0
- package/registry/nocobase-auth-cas/demo.tsx +20 -0
- package/registry/nocobase-auth-cas/extension.tsx +46 -0
- package/registry/nocobase-auth-cas/index.ts +1 -0
- package/registry/nocobase-auth-cas/use-cas-sign-in.ts +29 -0
- package/registry/nocobase-auth-dingtalk/README.md +7 -0
- package/registry/nocobase-auth-dingtalk/auto-login-provider.tsx +154 -0
- package/registry/nocobase-auth-dingtalk/demo.tsx +23 -0
- package/registry/nocobase-auth-dingtalk/dingtalk-sign-in-button.tsx +45 -0
- package/registry/nocobase-auth-dingtalk/extension.tsx +55 -0
- package/registry/nocobase-auth-dingtalk/index.ts +4 -0
- package/registry/nocobase-auth-dingtalk/use-dingtalk-sign-in.ts +64 -0
- package/registry/nocobase-auth-ldap/README.md +6 -0
- package/registry/nocobase-auth-ldap/demo.tsx +21 -0
- package/registry/nocobase-auth-ldap/extension.tsx +46 -0
- package/registry/nocobase-auth-ldap/index.ts +1 -0
- package/registry/nocobase-auth-ldap/ldap-sign-in-form.tsx +69 -0
- package/registry/nocobase-auth-ldap/use-ldap-sign-in.ts +5 -0
- package/registry/nocobase-auth-oidc/README.md +11 -0
- package/registry/nocobase-auth-oidc/auto-redirect-provider.tsx +13 -0
- package/registry/nocobase-auth-oidc/demo.tsx +20 -0
- package/registry/nocobase-auth-oidc/extension.tsx +51 -0
- package/registry/nocobase-auth-oidc/index.ts +1 -0
- package/registry/nocobase-auth-oidc/oidc-sign-in-button.tsx +44 -0
- package/registry/nocobase-auth-oidc/use-oidc-sign-in.ts +58 -0
- package/registry/nocobase-auth-saml/README.md +6 -0
- package/registry/nocobase-auth-saml/auto-redirect-provider.tsx +13 -0
- package/registry/nocobase-auth-saml/demo.tsx +20 -0
- package/registry/nocobase-auth-saml/extension.tsx +51 -0
- package/registry/nocobase-auth-saml/index.ts +1 -0
- package/registry/nocobase-auth-saml/saml-sign-in-button.tsx +43 -0
- package/registry/nocobase-auth-saml/use-saml-sign-in.ts +51 -0
- package/registry/nocobase-auth-sms/README.md +7 -0
- package/registry/nocobase-auth-sms/demo.tsx +25 -0
- package/registry/nocobase-auth-sms/extension.tsx +46 -0
- package/registry/nocobase-auth-sms/index.ts +1 -0
- package/registry/nocobase-auth-sms/sms-sign-in-form.tsx +107 -0
- package/registry/nocobase-auth-sms/use-sms-sign-in.ts +88 -0
- package/registry/nocobase-auth-wecom/README.md +6 -0
- package/registry/nocobase-auth-wecom/auto-login-provider.tsx +21 -0
- package/registry/nocobase-auth-wecom/demo.tsx +23 -0
- package/registry/nocobase-auth-wecom/extension.tsx +49 -0
- package/registry/nocobase-auth-wecom/index.ts +1 -0
- package/registry/nocobase-auth-wecom/use-wecom-sign-in.ts +62 -0
- package/registry/nocobase-auth-wecom/wecom-sign-in-button.tsx +70 -0
- package/registry/nocobase-i18n/demo/prompt-generator.tsx +30 -54
- package/registry/nocobase-route-surfaces/demo/prompt-generator.tsx +18 -21
- package/registry.config.json +112 -0
- package/scripts/build-html.mjs +106 -0
- package/src/App.tsx +34 -8
- package/src/app/extension.ts +4 -0
- package/src/app/extensions.tsx +24 -1
- package/src/components/auth/authenticator-adapters.ts +20 -0
- package/src/components/auth/auto-redirect-provider.tsx +84 -0
- package/src/components/auth/basic-sign-in-form.tsx +101 -0
- package/src/components/auth/default-sign-in-page.tsx +20 -0
- package/src/components/auth/demo/auth-demo-page.tsx +236 -0
- package/src/components/auth/demo/auth-demo-prompt-generator.tsx +93 -0
- package/src/components/auth/demo/auth-demo-route.tsx +11 -0
- package/src/components/auth/demo/auth-method-demo.tsx +48 -0
- package/src/components/auth/demo/index.ts +4 -0
- package/src/components/auth/dynamic-sign-in.tsx +191 -0
- package/src/components/auth/forgot-password-form.tsx +13 -5
- package/src/components/auth/index.ts +13 -0
- package/src/components/auth/sign-in-form.tsx +1 -111
- package/src/components/auth/sign-up-form.tsx +14 -37
- package/src/components/auth/types.ts +38 -0
- package/src/components/auth/use-authenticator-sign-in.ts +14 -0
- package/src/components/auth/use-public-authenticators.ts +26 -0
- package/src/components/data-table/data-table-filter.tsx +107 -153
- package/src/components/demo/prompt-output.tsx +71 -0
- package/src/components/ui/alert-dialog.tsx +2 -0
- package/src/components/ui/attachment.tsx +207 -0
- package/src/components/ui/bubble.tsx +128 -0
- package/src/components/ui/button-group.tsx +87 -0
- package/src/components/ui/button.tsx +6 -6
- package/src/components/ui/calendar.tsx +0 -2
- package/src/components/ui/card.tsx +1 -1
- package/src/components/ui/carousel.tsx +2 -0
- package/src/components/ui/combobox.tsx +297 -0
- package/src/components/ui/command.tsx +43 -41
- package/src/components/ui/dialog.tsx +0 -2
- package/src/components/ui/direction.tsx +4 -0
- package/src/components/ui/drawer.tsx +2 -0
- package/src/components/ui/dropdown-menu.tsx +0 -2
- package/src/components/ui/empty.tsx +104 -0
- package/src/components/ui/field.tsx +238 -0
- package/src/components/ui/hover-card.tsx +2 -0
- package/src/components/ui/input-group.tsx +0 -2
- package/src/components/ui/input-otp.tsx +0 -2
- package/src/components/ui/input.tsx +1 -1
- package/src/components/ui/item.tsx +201 -0
- package/src/components/ui/kbd.tsx +26 -0
- package/src/components/ui/label.tsx +2 -0
- package/src/components/ui/marker.tsx +71 -0
- package/src/components/ui/message-scroller.tsx +131 -0
- package/src/components/ui/message.tsx +92 -0
- package/src/components/ui/native-select.tsx +61 -0
- package/src/components/ui/popover.tsx +0 -2
- package/src/components/ui/progress.tsx +2 -0
- package/src/components/ui/radio-group.tsx +0 -2
- package/src/components/ui/resizable.tsx +2 -0
- package/src/components/ui/scroll-area.tsx +0 -2
- package/src/components/ui/select.tsx +6 -4
- package/src/components/ui/separator.tsx +0 -2
- package/src/components/ui/sheet.tsx +21 -22
- package/src/components/ui/sidebar.tsx +1 -3
- package/src/components/ui/sonner.tsx +2 -0
- package/src/components/ui/spinner.tsx +10 -0
- package/src/components/ui/switch.tsx +0 -2
- package/src/components/ui/table.tsx +4 -2
- package/src/components/ui/tabs.tsx +0 -2
- package/src/components/ui/textarea.tsx +1 -1
- package/src/components/ui/toggle-group.tsx +2 -0
- package/src/components/ui/toggle.tsx +2 -0
- package/src/components/ui/tooltip.tsx +0 -2
- package/src/index.tsx +3 -0
- package/src/lib/nocobase/client.ts +32 -2
- package/src/lib/utils.ts +2 -1
- package/src/locales/en-US.ts +4 -2
- package/src/locales/zh-CN.ts +4 -2
- package/src/pages/login/index.tsx +2 -2
- package/src/pages/users/list.tsx +144 -16
- package/src/providers/auth-callback.ts +21 -0
- package/src/providers/auth.ts +108 -22
- package/src/providers/constants.ts +4 -1
- package/src/providers/runtime-config.ts +19 -0
- package/src/vite-env.d.ts +5 -0
- package/vite.config.ts +55 -2
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useState, useEffect, useMemo } from "react";
|
|
3
|
+
import { lazy, Suspense, useState, useEffect, useMemo } from "react";
|
|
4
4
|
import { useTranslate, type CrudOperators } from "@refinedev/core";
|
|
5
5
|
import type { Column, Table as ReactTable } from "@tanstack/react-table";
|
|
6
6
|
import type { DateRange } from "react-day-picker";
|
|
7
|
-
import {
|
|
7
|
+
import { ChevronsUpDown, ListFilter, X } from "lucide-react";
|
|
8
8
|
|
|
9
9
|
import { Button } from "@/components/ui/button";
|
|
10
10
|
import { Input } from "@/components/ui/input";
|
|
11
|
-
import { Badge } from "@/components/ui/badge";
|
|
12
11
|
import {
|
|
13
12
|
Popover,
|
|
14
13
|
PopoverContent,
|
|
@@ -22,9 +21,15 @@ import {
|
|
|
22
21
|
CommandList,
|
|
23
22
|
} from "@/components/ui/command";
|
|
24
23
|
import { Separator } from "@/components/ui/separator";
|
|
25
|
-
import {
|
|
24
|
+
import { LoadingState } from "@/components/app-shell/loading-state";
|
|
26
25
|
import { cn } from "@/lib/utils";
|
|
27
26
|
|
|
27
|
+
const Calendar = lazy(() =>
|
|
28
|
+
import("@/components/ui/calendar").then((module) => ({
|
|
29
|
+
default: module.Calendar,
|
|
30
|
+
}))
|
|
31
|
+
);
|
|
32
|
+
|
|
28
33
|
export type DataTableFilterDropdownProps<TData> = {
|
|
29
34
|
column: Column<TData>;
|
|
30
35
|
contentClassName?: string;
|
|
@@ -54,22 +59,29 @@ export function DataTableFilterDropdown<TData>({
|
|
|
54
59
|
variant="ghost"
|
|
55
60
|
size="icon"
|
|
56
61
|
className={cn(
|
|
57
|
-
"data-[state=open]:bg-accent",
|
|
58
62
|
"w-5 h-5",
|
|
59
63
|
{
|
|
60
|
-
"text-primary":
|
|
61
|
-
|
|
64
|
+
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90 data-[state=open]:bg-primary/90 data-[state=open]:text-primary-foreground":
|
|
65
|
+
isFiltered,
|
|
66
|
+
"text-muted-foreground data-[state=open]:bg-accent":
|
|
67
|
+
!isFiltered,
|
|
62
68
|
},
|
|
63
69
|
triggerClassName
|
|
64
70
|
)}
|
|
65
71
|
/>
|
|
66
72
|
}
|
|
67
73
|
>
|
|
68
|
-
<ListFilter
|
|
74
|
+
<ListFilter
|
|
75
|
+
className={cn("!h-3", "!w-3", isFiltered && "stroke-[2.5]")}
|
|
76
|
+
/>
|
|
69
77
|
</PopoverTrigger>
|
|
70
78
|
<PopoverContent
|
|
71
79
|
align="start"
|
|
72
|
-
className={cn(
|
|
80
|
+
className={cn(
|
|
81
|
+
"w-80 max-w-[calc(100vw-2rem)]",
|
|
82
|
+
"shadow-sm",
|
|
83
|
+
contentClassName
|
|
84
|
+
)}
|
|
73
85
|
>
|
|
74
86
|
{children({ isOpen, setIsOpen })}
|
|
75
87
|
</PopoverContent>
|
|
@@ -287,12 +299,10 @@ export function DataTableFilterCombobox<TData>({
|
|
|
287
299
|
}
|
|
288
300
|
};
|
|
289
301
|
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
};
|
|
302
|
+
const selectedLabels = currentValues.map((value) => {
|
|
303
|
+
const option = options.find((item) => item.value === value);
|
|
304
|
+
return option?.label ?? value;
|
|
305
|
+
});
|
|
296
306
|
|
|
297
307
|
const getDisplayText = () => {
|
|
298
308
|
if (currentValues.length === 0) {
|
|
@@ -302,7 +312,7 @@ export function DataTableFilterCombobox<TData>({
|
|
|
302
312
|
}
|
|
303
313
|
|
|
304
314
|
if (multiple) {
|
|
305
|
-
return
|
|
315
|
+
return selectedLabels.join(", ");
|
|
306
316
|
}
|
|
307
317
|
|
|
308
318
|
const selectedOption = options.find(
|
|
@@ -311,13 +321,6 @@ export function DataTableFilterCombobox<TData>({
|
|
|
311
321
|
return selectedOption ? selectedOption.label : currentValues[0];
|
|
312
322
|
};
|
|
313
323
|
|
|
314
|
-
const getSelectedLabels = () => {
|
|
315
|
-
return currentValues.map((val) => {
|
|
316
|
-
const option = options.find((opt) => opt.value === val);
|
|
317
|
-
return { label: option ? option.label : val, value: val };
|
|
318
|
-
});
|
|
319
|
-
};
|
|
320
|
-
|
|
321
324
|
return (
|
|
322
325
|
<Popover open={isOpen} onOpenChange={setIsOpen}>
|
|
323
326
|
<PopoverTrigger
|
|
@@ -328,93 +331,37 @@ export function DataTableFilterCombobox<TData>({
|
|
|
328
331
|
aria-expanded={isOpen}
|
|
329
332
|
className={cn(
|
|
330
333
|
"w-full",
|
|
331
|
-
"min-w-
|
|
332
|
-
"max-w-80",
|
|
334
|
+
"min-w-0",
|
|
333
335
|
"justify-start",
|
|
334
|
-
"h-
|
|
335
|
-
"min-h-9"
|
|
336
|
+
"h-8"
|
|
336
337
|
)}
|
|
337
338
|
/>
|
|
338
339
|
}
|
|
339
340
|
>
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
className={cn(
|
|
350
|
-
"inline-flex",
|
|
351
|
-
"items-center",
|
|
352
|
-
"gap-0",
|
|
353
|
-
"h-4",
|
|
354
|
-
"pr-0.5",
|
|
355
|
-
"rounded-sm"
|
|
356
|
-
)}
|
|
357
|
-
>
|
|
358
|
-
<span className={cn("text-[10px]", "leading-4")}>
|
|
359
|
-
{label}
|
|
360
|
-
</span>
|
|
361
|
-
<span
|
|
362
|
-
className={cn(
|
|
363
|
-
"inline-flex",
|
|
364
|
-
"items-center",
|
|
365
|
-
"justify-center",
|
|
366
|
-
"p-0",
|
|
367
|
-
"w-4",
|
|
368
|
-
"h-full",
|
|
369
|
-
"text-muted-foreground",
|
|
370
|
-
"hover:text-destructive",
|
|
371
|
-
"rounded-sm",
|
|
372
|
-
"cursor-pointer",
|
|
373
|
-
"transition-colors"
|
|
374
|
-
)}
|
|
375
|
-
onClick={(e) => {
|
|
376
|
-
e.preventDefault();
|
|
377
|
-
e.stopPropagation();
|
|
378
|
-
handleRemove(val);
|
|
379
|
-
}}
|
|
380
|
-
>
|
|
381
|
-
<X className={cn("!h-2", "!w-2")} />
|
|
382
|
-
</span>
|
|
383
|
-
</Badge>
|
|
384
|
-
))}
|
|
385
|
-
{currentValues.length > 3 && (
|
|
386
|
-
<span
|
|
387
|
-
className={cn(
|
|
388
|
-
"text-xs",
|
|
389
|
-
"text-muted-foreground",
|
|
390
|
-
"px-1"
|
|
391
|
-
)}
|
|
392
|
-
>
|
|
393
|
-
+{currentValues.length - 3} more
|
|
394
|
-
</span>
|
|
395
|
-
)}
|
|
396
|
-
</div>
|
|
397
|
-
) : (
|
|
398
|
-
<span
|
|
399
|
-
className={cn(
|
|
400
|
-
"truncate",
|
|
401
|
-
"flex-1",
|
|
402
|
-
"text-start",
|
|
403
|
-
"text-xs",
|
|
404
|
-
currentValues.length === 0 && "text-muted-foreground"
|
|
405
|
-
)}
|
|
406
|
-
>
|
|
407
|
-
{getDisplayText()}
|
|
408
|
-
</span>
|
|
341
|
+
<div className={cn("flex", "min-w-0", "w-full", "gap-2")}>
|
|
342
|
+
<span
|
|
343
|
+
className={cn(
|
|
344
|
+
"min-w-0",
|
|
345
|
+
"truncate",
|
|
346
|
+
"flex-1",
|
|
347
|
+
"text-start",
|
|
348
|
+
"text-xs",
|
|
349
|
+
currentValues.length === 0 && "text-muted-foreground"
|
|
409
350
|
)}
|
|
351
|
+
>
|
|
352
|
+
{getDisplayText()}
|
|
353
|
+
</span>
|
|
410
354
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
355
|
+
<ChevronsUpDown
|
|
356
|
+
className={cn("h-4", "w-4", "shrink-0", "opacity-50")}
|
|
357
|
+
/>
|
|
358
|
+
</div>
|
|
415
359
|
</PopoverTrigger>
|
|
416
|
-
<PopoverContent
|
|
417
|
-
|
|
360
|
+
<PopoverContent
|
|
361
|
+
className="w-(--anchor-width) min-w-56 p-0"
|
|
362
|
+
align="start"
|
|
363
|
+
>
|
|
364
|
+
<Command>
|
|
418
365
|
<CommandInput
|
|
419
366
|
placeholder={t("table.filter.combobox.search", "Search...")}
|
|
420
367
|
/>
|
|
@@ -426,25 +373,16 @@ export function DataTableFilterCombobox<TData>({
|
|
|
426
373
|
)}
|
|
427
374
|
</CommandEmpty>
|
|
428
375
|
<CommandList>
|
|
429
|
-
{(option
|
|
376
|
+
{options.map((option) => (
|
|
430
377
|
<CommandItem
|
|
431
378
|
key={option.value}
|
|
432
|
-
value={option}
|
|
433
|
-
|
|
379
|
+
value={`${option.label} ${option.value}`}
|
|
380
|
+
data-checked={currentValues.includes(option.value)}
|
|
381
|
+
onSelect={() => handleSelect(option.value)}
|
|
434
382
|
>
|
|
435
383
|
{option.label}
|
|
436
|
-
<Check
|
|
437
|
-
className={cn(
|
|
438
|
-
"ml-auto",
|
|
439
|
-
"h-4",
|
|
440
|
-
"w-4",
|
|
441
|
-
currentValues.includes(option.value)
|
|
442
|
-
? "opacity-100"
|
|
443
|
-
: "opacity-0"
|
|
444
|
-
)}
|
|
445
|
-
/>
|
|
446
384
|
</CommandItem>
|
|
447
|
-
)}
|
|
385
|
+
))}
|
|
448
386
|
</CommandList>
|
|
449
387
|
</Command>
|
|
450
388
|
</PopoverContent>
|
|
@@ -518,13 +456,15 @@ export function DataTableFilterDropdownDateSinglePicker<TData>({
|
|
|
518
456
|
}
|
|
519
457
|
}}
|
|
520
458
|
>
|
|
521
|
-
<
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
459
|
+
<Suspense fallback={<LoadingState className="min-h-72" />}>
|
|
460
|
+
<Calendar
|
|
461
|
+
mode="single"
|
|
462
|
+
selected={filterValue}
|
|
463
|
+
onSelect={(date) => {
|
|
464
|
+
setFilterValue(date);
|
|
465
|
+
}}
|
|
466
|
+
/>
|
|
467
|
+
</Suspense>
|
|
528
468
|
|
|
529
469
|
<div className={cn("w-full")}>
|
|
530
470
|
<Separator />
|
|
@@ -626,17 +566,19 @@ export function DataTableFilterDropdownDateRangePicker<TData>({
|
|
|
626
566
|
}
|
|
627
567
|
}}
|
|
628
568
|
>
|
|
629
|
-
<
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
569
|
+
<Suspense fallback={<LoadingState className="min-h-72" />}>
|
|
570
|
+
<Calendar
|
|
571
|
+
mode="range"
|
|
572
|
+
numberOfMonths={2}
|
|
573
|
+
selected={filterValue}
|
|
574
|
+
onSelect={(date) => {
|
|
575
|
+
setFilterValue({
|
|
576
|
+
from: date?.from,
|
|
577
|
+
to: date?.to,
|
|
578
|
+
});
|
|
579
|
+
}}
|
|
580
|
+
/>
|
|
581
|
+
</Suspense>
|
|
640
582
|
|
|
641
583
|
<div className={cn("w-full")}>
|
|
642
584
|
<Separator />
|
|
@@ -680,6 +622,9 @@ export function DataTableFilterInput<TData>({
|
|
|
680
622
|
defaultOperator: defaultOperatorFromProps,
|
|
681
623
|
renderInput,
|
|
682
624
|
}: DataTableFilterInputProps<TData>) {
|
|
625
|
+
const hasOperatorSelect = Boolean(
|
|
626
|
+
operatorsFromProps && operatorsFromProps.length > 1
|
|
627
|
+
);
|
|
683
628
|
const [filterValue, setFilterValue] = useState(
|
|
684
629
|
(columnFromProps.getFilterValue() as string | string[]) || ""
|
|
685
630
|
);
|
|
@@ -720,7 +665,14 @@ export function DataTableFilterInput<TData>({
|
|
|
720
665
|
};
|
|
721
666
|
|
|
722
667
|
return (
|
|
723
|
-
<DataTableFilterDropdown
|
|
668
|
+
<DataTableFilterDropdown
|
|
669
|
+
column={columnFromProps}
|
|
670
|
+
contentClassName={
|
|
671
|
+
hasOperatorSelect
|
|
672
|
+
? "w-[30rem] max-w-[calc(100vw-2rem)]"
|
|
673
|
+
: undefined
|
|
674
|
+
}
|
|
675
|
+
>
|
|
724
676
|
{({ setIsOpen }) => {
|
|
725
677
|
return (
|
|
726
678
|
<div
|
|
@@ -739,9 +691,15 @@ export function DataTableFilterInput<TData>({
|
|
|
739
691
|
}}
|
|
740
692
|
>
|
|
741
693
|
<div
|
|
742
|
-
className={cn(
|
|
694
|
+
className={cn(
|
|
695
|
+
"grid",
|
|
696
|
+
"grid-cols-1",
|
|
697
|
+
"w-full",
|
|
698
|
+
"gap-2",
|
|
699
|
+
hasOperatorSelect && "md:grid-cols-2"
|
|
700
|
+
)}
|
|
743
701
|
>
|
|
744
|
-
{
|
|
702
|
+
{hasOperatorSelect && (
|
|
745
703
|
<DataTableFilterOperatorSelect
|
|
746
704
|
value={operator}
|
|
747
705
|
operators={operatorsFromProps}
|
|
@@ -791,11 +749,11 @@ const CRUD_OPERATOR_LABELS: Record<
|
|
|
791
749
|
},
|
|
792
750
|
in: {
|
|
793
751
|
i18nKey: "table.filter.operator.in",
|
|
794
|
-
defaultLabel: "Includes
|
|
752
|
+
defaultLabel: "Includes",
|
|
795
753
|
},
|
|
796
754
|
nin: {
|
|
797
755
|
i18nKey: "table.filter.operator.nin",
|
|
798
|
-
defaultLabel: "
|
|
756
|
+
defaultLabel: "Excludes",
|
|
799
757
|
},
|
|
800
758
|
ina: {
|
|
801
759
|
i18nKey: "table.filter.operator.ina",
|
|
@@ -948,31 +906,27 @@ export function DataTableFilterOperatorSelect({
|
|
|
948
906
|
className={cn("ml-2", "h-4", "w-4", "shrink-0", "opacity-50")}
|
|
949
907
|
/>
|
|
950
908
|
</PopoverTrigger>
|
|
951
|
-
<PopoverContent
|
|
952
|
-
|
|
909
|
+
<PopoverContent
|
|
910
|
+
className={cn("w-(--anchor-width) p-0", contentClassName)}
|
|
911
|
+
keepMounted
|
|
912
|
+
>
|
|
913
|
+
<Command>
|
|
953
914
|
<CommandInput placeholder={placeholderText} />
|
|
954
915
|
<CommandEmpty>{noResultsText}</CommandEmpty>
|
|
955
916
|
<CommandList>
|
|
956
|
-
{(option
|
|
917
|
+
{operatorOptions.map((option) => (
|
|
957
918
|
<CommandItem
|
|
958
919
|
key={option.value}
|
|
959
|
-
value={option}
|
|
960
|
-
|
|
920
|
+
value={`${option.label} ${option.value}`}
|
|
921
|
+
data-checked={value === option.value}
|
|
922
|
+
onSelect={() => {
|
|
961
923
|
onValueChange(option.value);
|
|
962
924
|
setOpen(false);
|
|
963
925
|
}}
|
|
964
926
|
>
|
|
965
|
-
<Check
|
|
966
|
-
className={cn(
|
|
967
|
-
"mr-2",
|
|
968
|
-
"h-4",
|
|
969
|
-
"w-4",
|
|
970
|
-
value === option.value ? "opacity-100" : "opacity-0"
|
|
971
|
-
)}
|
|
972
|
-
/>
|
|
973
927
|
{option.label}
|
|
974
928
|
</CommandItem>
|
|
975
|
-
)}
|
|
929
|
+
))}
|
|
976
930
|
</CommandList>
|
|
977
931
|
</Command>
|
|
978
932
|
</PopoverContent>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { useState, type ReactNode } from "react";
|
|
2
|
+
import { Check, Copy } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
import { Button } from "@/components/ui/button";
|
|
5
|
+
import { Card } from "@/components/ui/card";
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
export function PromptOutput({
|
|
9
|
+
className,
|
|
10
|
+
copiedLabel = "Copied",
|
|
11
|
+
copyErrorLabel = "Clipboard access failed. Select the prompt and copy it manually.",
|
|
12
|
+
copyLabel = "Copy prompt",
|
|
13
|
+
description,
|
|
14
|
+
prompt,
|
|
15
|
+
promptClassName,
|
|
16
|
+
title = "Generated prompt",
|
|
17
|
+
}: {
|
|
18
|
+
className?: string;
|
|
19
|
+
copiedLabel?: ReactNode;
|
|
20
|
+
copyErrorLabel?: ReactNode;
|
|
21
|
+
copyLabel?: ReactNode;
|
|
22
|
+
description: ReactNode;
|
|
23
|
+
prompt: string;
|
|
24
|
+
promptClassName?: string;
|
|
25
|
+
title?: ReactNode;
|
|
26
|
+
}) {
|
|
27
|
+
const [copied, setCopied] = useState(false);
|
|
28
|
+
const [copyError, setCopyError] = useState(false);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Card className={cn("min-w-0 gap-0 overflow-hidden py-0", className)}>
|
|
32
|
+
<div className="flex items-center justify-between gap-3 border-b px-4 py-3">
|
|
33
|
+
<div className="min-w-0">
|
|
34
|
+
<div className="text-sm font-medium">{title}</div>
|
|
35
|
+
<div className="text-xs text-muted-foreground">{description}</div>
|
|
36
|
+
</div>
|
|
37
|
+
<Button
|
|
38
|
+
type="button"
|
|
39
|
+
size="sm"
|
|
40
|
+
className="shrink-0"
|
|
41
|
+
onClick={async () => {
|
|
42
|
+
try {
|
|
43
|
+
await navigator.clipboard.writeText(prompt);
|
|
44
|
+
setCopyError(false);
|
|
45
|
+
setCopied(true);
|
|
46
|
+
window.setTimeout(() => setCopied(false), 1500);
|
|
47
|
+
} catch {
|
|
48
|
+
setCopyError(true);
|
|
49
|
+
}
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
{copied ? <Check /> : <Copy />}
|
|
53
|
+
{copied ? copiedLabel : copyLabel}
|
|
54
|
+
</Button>
|
|
55
|
+
</div>
|
|
56
|
+
{copyError ? (
|
|
57
|
+
<p className="border-b px-4 py-2 text-xs text-destructive">
|
|
58
|
+
{copyErrorLabel}
|
|
59
|
+
</p>
|
|
60
|
+
) : null}
|
|
61
|
+
<pre
|
|
62
|
+
className={cn(
|
|
63
|
+
"max-h-[560px] overflow-auto whitespace-pre-wrap bg-muted/25 p-5 font-mono text-xs leading-5 text-muted-foreground",
|
|
64
|
+
promptClassName
|
|
65
|
+
)}
|
|
66
|
+
>
|
|
67
|
+
{prompt}
|
|
68
|
+
</pre>
|
|
69
|
+
</Card>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { mergeProps } from "@base-ui/react/merge-props"
|
|
3
|
+
import { useRender } from "@base-ui/react/use-render"
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
import { Button } from "@/components/ui/button"
|
|
8
|
+
|
|
9
|
+
const attachmentVariants = cva(
|
|
10
|
+
"group/attachment relative flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-xl border bg-card text-card-foreground transition-colors focus-within:ring-1 focus-within:ring-ring/50 has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed",
|
|
11
|
+
{
|
|
12
|
+
variants: {
|
|
13
|
+
size: {
|
|
14
|
+
default:
|
|
15
|
+
"gap-2 text-sm has-data-[slot=attachment-content]:px-2.5 has-data-[slot=attachment-content]:py-2 has-data-[slot=attachment-media]:p-2",
|
|
16
|
+
sm: "gap-2.5 text-xs has-data-[slot=attachment-content]:px-2 has-data-[slot=attachment-content]:py-1.5 has-data-[slot=attachment-media]:p-1.5",
|
|
17
|
+
xs: "gap-1.5 rounded-lg text-xs has-data-[slot=attachment-content]:px-1.5 has-data-[slot=attachment-content]:py-1 has-data-[slot=attachment-media]:p-1",
|
|
18
|
+
},
|
|
19
|
+
orientation: {
|
|
20
|
+
horizontal: "min-w-40 items-center",
|
|
21
|
+
vertical: "w-24 flex-col has-data-[slot=attachment-content]:w-30",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
function Attachment({
|
|
28
|
+
className,
|
|
29
|
+
state = "done",
|
|
30
|
+
size = "default",
|
|
31
|
+
orientation = "horizontal",
|
|
32
|
+
...props
|
|
33
|
+
}: React.ComponentProps<"div"> &
|
|
34
|
+
VariantProps<typeof attachmentVariants> & {
|
|
35
|
+
state?: "idle" | "uploading" | "processing" | "error" | "done"
|
|
36
|
+
}) {
|
|
37
|
+
return (
|
|
38
|
+
<div
|
|
39
|
+
data-slot="attachment"
|
|
40
|
+
data-state={state}
|
|
41
|
+
data-size={size}
|
|
42
|
+
data-orientation={orientation}
|
|
43
|
+
className={cn(attachmentVariants({ size, orientation }), className)}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const attachmentMediaVariants = cva(
|
|
50
|
+
"relative flex aspect-square w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted text-foreground group-data-[orientation=vertical]/attachment:w-full group-data-[size=sm]/attachment:w-8 group-data-[size=xs]/attachment:w-7 group-data-[size=xs]/attachment:rounded-md group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive group-data-[orientation=vertical]/attachment:*:data-[slot=spinner]:size-6! [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-6 group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-3.5",
|
|
51
|
+
{
|
|
52
|
+
variants: {
|
|
53
|
+
variant: {
|
|
54
|
+
icon: "",
|
|
55
|
+
image:
|
|
56
|
+
"opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
defaultVariants: {
|
|
60
|
+
variant: "icon",
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
function AttachmentMedia({
|
|
66
|
+
className,
|
|
67
|
+
variant = "icon",
|
|
68
|
+
...props
|
|
69
|
+
}: React.ComponentProps<"div"> & VariantProps<typeof attachmentMediaVariants>) {
|
|
70
|
+
return (
|
|
71
|
+
<div
|
|
72
|
+
data-slot="attachment-media"
|
|
73
|
+
data-variant={variant}
|
|
74
|
+
className={cn(attachmentMediaVariants({ variant }), className)}
|
|
75
|
+
{...props}
|
|
76
|
+
/>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function AttachmentContent({
|
|
81
|
+
className,
|
|
82
|
+
...props
|
|
83
|
+
}: React.ComponentProps<"div">) {
|
|
84
|
+
return (
|
|
85
|
+
<div
|
|
86
|
+
data-slot="attachment-content"
|
|
87
|
+
className={cn(
|
|
88
|
+
"max-w-full min-w-0 flex-1 leading-tight group-data-[orientation=vertical]/attachment:px-1",
|
|
89
|
+
className
|
|
90
|
+
)}
|
|
91
|
+
{...props}
|
|
92
|
+
/>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function AttachmentTitle({
|
|
97
|
+
className,
|
|
98
|
+
...props
|
|
99
|
+
}: React.ComponentProps<"span">) {
|
|
100
|
+
return (
|
|
101
|
+
<span
|
|
102
|
+
data-slot="attachment-title"
|
|
103
|
+
className={cn(
|
|
104
|
+
"block max-w-full min-w-0 truncate font-medium group-data-[state=processing]/attachment:shimmer group-data-[state=uploading]/attachment:shimmer",
|
|
105
|
+
className
|
|
106
|
+
)}
|
|
107
|
+
{...props}
|
|
108
|
+
/>
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function AttachmentDescription({
|
|
113
|
+
className,
|
|
114
|
+
...props
|
|
115
|
+
}: React.ComponentProps<"span">) {
|
|
116
|
+
return (
|
|
117
|
+
<span
|
|
118
|
+
data-slot="attachment-description"
|
|
119
|
+
className={cn(
|
|
120
|
+
"mt-0.5 block min-w-0 truncate text-xs text-muted-foreground group-data-[state=error]/attachment:text-destructive/80",
|
|
121
|
+
"max-w-full",
|
|
122
|
+
className
|
|
123
|
+
)}
|
|
124
|
+
{...props}
|
|
125
|
+
/>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function AttachmentActions({
|
|
130
|
+
className,
|
|
131
|
+
...props
|
|
132
|
+
}: React.ComponentProps<"div">) {
|
|
133
|
+
return (
|
|
134
|
+
<div
|
|
135
|
+
data-slot="attachment-actions"
|
|
136
|
+
className={cn(
|
|
137
|
+
"relative z-20 flex shrink-0 items-center group-data-[orientation=vertical]/attachment:absolute group-data-[orientation=vertical]/attachment:top-3 group-data-[orientation=vertical]/attachment:right-3 group-data-[orientation=vertical]/attachment:gap-1",
|
|
138
|
+
className
|
|
139
|
+
)}
|
|
140
|
+
{...props}
|
|
141
|
+
/>
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function AttachmentAction({
|
|
146
|
+
className,
|
|
147
|
+
variant,
|
|
148
|
+
size = "icon-xs",
|
|
149
|
+
...props
|
|
150
|
+
}: React.ComponentProps<typeof Button>) {
|
|
151
|
+
return (
|
|
152
|
+
<Button
|
|
153
|
+
data-slot="attachment-action"
|
|
154
|
+
variant={variant ?? "ghost"}
|
|
155
|
+
size={size}
|
|
156
|
+
className={cn(className)}
|
|
157
|
+
{...props}
|
|
158
|
+
/>
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function AttachmentTrigger({
|
|
163
|
+
className,
|
|
164
|
+
render,
|
|
165
|
+
type,
|
|
166
|
+
...props
|
|
167
|
+
}: useRender.ComponentProps<"button">) {
|
|
168
|
+
return useRender({
|
|
169
|
+
defaultTagName: "button",
|
|
170
|
+
props: mergeProps<"button">(
|
|
171
|
+
{
|
|
172
|
+
type: render ? type : (type ?? "button"),
|
|
173
|
+
className: cn("absolute inset-0 z-10 outline-none", className),
|
|
174
|
+
},
|
|
175
|
+
props
|
|
176
|
+
),
|
|
177
|
+
render,
|
|
178
|
+
state: {
|
|
179
|
+
slot: "attachment-trigger",
|
|
180
|
+
},
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function AttachmentGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
185
|
+
return (
|
|
186
|
+
<div
|
|
187
|
+
data-slot="attachment-group"
|
|
188
|
+
className={cn(
|
|
189
|
+
"flex min-w-0 scroll-fade-x snap-x snap-mandatory scroll-px-1 scrollbar-none gap-3 overflow-x-auto overscroll-x-contain py-1 *:data-[slot=attachment]:flex-none *:data-[slot=attachment]:snap-start",
|
|
190
|
+
className
|
|
191
|
+
)}
|
|
192
|
+
{...props}
|
|
193
|
+
/>
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export {
|
|
198
|
+
Attachment,
|
|
199
|
+
AttachmentGroup,
|
|
200
|
+
AttachmentMedia,
|
|
201
|
+
AttachmentContent,
|
|
202
|
+
AttachmentTitle,
|
|
203
|
+
AttachmentDescription,
|
|
204
|
+
AttachmentActions,
|
|
205
|
+
AttachmentAction,
|
|
206
|
+
AttachmentTrigger,
|
|
207
|
+
}
|