@nestledjs/data-browser 0.1.17 → 0.1.20
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/lib/components/RelationFieldWrapper.js +35 -22
- package/lib/components/filters/DateRangeFilter.js +39 -48
- package/lib/components/filters/NumberRangeFilter.js +43 -48
- package/lib/components/filters/RelationComponents.js +96 -102
- package/lib/components/filters/RelationFilterField.js +50 -47
- package/lib/components/shared/AdminBreadcrumbs.js +41 -45
- package/lib/components/shared/AdminErrorStates.js +47 -93
- package/lib/components/shared/AdminStatusDisplay.js +29 -36
- package/lib/context/AdminDataContext.js +10 -14
- package/lib/layouts/AdminDataLayout.js +90 -177
- package/lib/pages/AdminDataCreatePage.js +141 -267
- package/lib/pages/AdminDataEditPage.js +258 -460
- package/lib/pages/AdminDataIndexPage.js +31 -55
- package/lib/pages/AdminDataListPage.js +583 -597
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
1
2
|
import { Link } from "react-router";
|
|
2
3
|
import { useState, useEffect } from "react";
|
|
3
|
-
var _jsxFileName = "/Users/justinhandley/IdeaProjects/nestled_template/libs/data-browser/src/lib/components/RelationFieldWrapper.tsx";
|
|
4
4
|
const toKebabCase = (str) => {
|
|
5
5
|
return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
6
6
|
};
|
|
@@ -36,27 +36,40 @@ function RelationFieldWrapper({
|
|
|
36
36
|
}
|
|
37
37
|
}, [fieldName, currentValue, initialValue]);
|
|
38
38
|
const showViewLink = !!(relationType && currentValue && currentValue !== "");
|
|
39
|
-
return /* @__PURE__ */
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
39
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
40
|
+
children,
|
|
41
|
+
showViewLink && /* @__PURE__ */ jsx("div", { className: "mt-1", children: /* @__PURE__ */ jsxs(
|
|
42
|
+
Link,
|
|
43
|
+
{
|
|
44
|
+
to: `${basePath}/${toKebabCase(relationType)}/${currentValue}`,
|
|
45
|
+
className: "inline-flex items-center text-xs text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 hover:underline",
|
|
46
|
+
children: [
|
|
47
|
+
/* @__PURE__ */ jsx(
|
|
48
|
+
"svg",
|
|
49
|
+
{
|
|
50
|
+
className: "h-3 w-3 mr-1",
|
|
51
|
+
fill: "none",
|
|
52
|
+
stroke: "currentColor",
|
|
53
|
+
viewBox: "0 0 24 24",
|
|
54
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
55
|
+
children: /* @__PURE__ */ jsx(
|
|
56
|
+
"path",
|
|
57
|
+
{
|
|
58
|
+
strokeLinecap: "round",
|
|
59
|
+
strokeLinejoin: "round",
|
|
60
|
+
strokeWidth: 2,
|
|
61
|
+
d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
),
|
|
66
|
+
"View ",
|
|
67
|
+
relationType,
|
|
68
|
+
" record"
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
) })
|
|
72
|
+
] });
|
|
60
73
|
}
|
|
61
74
|
export {
|
|
62
75
|
RelationFieldWrapper
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
1
2
|
import { formatFieldName } from "../../utils/string-utils.js";
|
|
2
|
-
var _jsxFileName = "/Users/justinhandley/IdeaProjects/nestled_template/libs/data-browser/src/lib/components/filters/DateRangeFilter.tsx";
|
|
3
3
|
function DateRangeFilter({
|
|
4
4
|
fieldName,
|
|
5
5
|
currentValue,
|
|
@@ -8,9 +8,7 @@ function DateRangeFilter({
|
|
|
8
8
|
const fromDate = (currentValue == null ? void 0 : currentValue.gte) ? new Date(currentValue.gte).toISOString().split("T")[0] : "";
|
|
9
9
|
const toDate = (currentValue == null ? void 0 : currentValue.lte) ? new Date(currentValue.lte).toISOString().split("T")[0] : "";
|
|
10
10
|
const handleFromChange = (date) => {
|
|
11
|
-
const newValue = {
|
|
12
|
-
...currentValue
|
|
13
|
-
};
|
|
11
|
+
const newValue = { ...currentValue };
|
|
14
12
|
if (date) {
|
|
15
13
|
newValue.gte = new Date(date).toISOString();
|
|
16
14
|
} else {
|
|
@@ -23,9 +21,7 @@ function DateRangeFilter({
|
|
|
23
21
|
}
|
|
24
22
|
};
|
|
25
23
|
const handleToChange = (date) => {
|
|
26
|
-
const newValue = {
|
|
27
|
-
...currentValue
|
|
28
|
-
};
|
|
24
|
+
const newValue = { ...currentValue };
|
|
29
25
|
if (date) {
|
|
30
26
|
const endOfDay = new Date(date);
|
|
31
27
|
endOfDay.setHours(23, 59, 59, 999);
|
|
@@ -39,47 +35,42 @@ function DateRangeFilter({
|
|
|
39
35
|
onChange(newValue);
|
|
40
36
|
}
|
|
41
37
|
};
|
|
42
|
-
return /* @__PURE__ */
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
} }))), (fromDate || toDate) && /* @__PURE__ */ React.createElement("div", { className: "text-xs text-gray-500", __self: this, __source: {
|
|
79
|
-
fileName: _jsxFileName,
|
|
80
|
-
lineNumber: 82,
|
|
81
|
-
columnNumber: 9
|
|
82
|
-
} }, fromDate && toDate && `${fromDate} to ${toDate}`, fromDate && !toDate && `From ${fromDate}`, !fromDate && toDate && `Until ${toDate}`));
|
|
38
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
39
|
+
/* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700", children: formatFieldName(fieldName) }),
|
|
40
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
41
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
42
|
+
/* @__PURE__ */ jsx("label", { htmlFor: `${fieldName}-from`, className: "block text-xs text-gray-500 mb-1", children: "From" }),
|
|
43
|
+
/* @__PURE__ */ jsx(
|
|
44
|
+
"input",
|
|
45
|
+
{
|
|
46
|
+
id: `${fieldName}-from`,
|
|
47
|
+
type: "date",
|
|
48
|
+
value: fromDate,
|
|
49
|
+
onChange: (e) => handleFromChange(e.target.value),
|
|
50
|
+
className: "w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-1 focus:ring-green-web focus:border-green-web"
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
] }),
|
|
54
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
55
|
+
/* @__PURE__ */ jsx("label", { htmlFor: `${fieldName}-to`, className: "block text-xs text-gray-500 mb-1", children: "To" }),
|
|
56
|
+
/* @__PURE__ */ jsx(
|
|
57
|
+
"input",
|
|
58
|
+
{
|
|
59
|
+
id: `${fieldName}-to`,
|
|
60
|
+
type: "date",
|
|
61
|
+
value: toDate,
|
|
62
|
+
onChange: (e) => handleToChange(e.target.value),
|
|
63
|
+
className: "w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-1 focus:ring-green-web focus:border-green-web"
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
] })
|
|
67
|
+
] }),
|
|
68
|
+
(fromDate || toDate) && /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-500", children: [
|
|
69
|
+
fromDate && toDate && `${fromDate} to ${toDate}`,
|
|
70
|
+
fromDate && !toDate && `From ${fromDate}`,
|
|
71
|
+
!fromDate && toDate && `Until ${toDate}`
|
|
72
|
+
] })
|
|
73
|
+
] });
|
|
83
74
|
}
|
|
84
75
|
export {
|
|
85
76
|
DateRangeFilter
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
1
2
|
import { formatFieldName } from "../../utils/string-utils.js";
|
|
2
|
-
var _jsxFileName = "/Users/justinhandley/IdeaProjects/nestled_template/libs/data-browser/src/lib/components/filters/NumberRangeFilter.tsx";
|
|
3
3
|
function NumberRangeFilter({
|
|
4
4
|
fieldName,
|
|
5
5
|
fieldType,
|
|
@@ -20,9 +20,7 @@ function NumberRangeFilter({
|
|
|
20
20
|
return void 0;
|
|
21
21
|
};
|
|
22
22
|
const handleMinChange = (value) => {
|
|
23
|
-
const newValue = {
|
|
24
|
-
...currentValue
|
|
25
|
-
};
|
|
23
|
+
const newValue = { ...currentValue };
|
|
26
24
|
const parsedValue = parseNumber(value);
|
|
27
25
|
if (parsedValue === void 0) {
|
|
28
26
|
delete newValue.gte;
|
|
@@ -36,9 +34,7 @@ function NumberRangeFilter({
|
|
|
36
34
|
}
|
|
37
35
|
};
|
|
38
36
|
const handleMaxChange = (value) => {
|
|
39
|
-
const newValue = {
|
|
40
|
-
...currentValue
|
|
41
|
-
};
|
|
37
|
+
const newValue = { ...currentValue };
|
|
42
38
|
const parsedValue = parseNumber(value);
|
|
43
39
|
if (parsedValue === void 0) {
|
|
44
40
|
delete newValue.lte;
|
|
@@ -52,47 +48,46 @@ function NumberRangeFilter({
|
|
|
52
48
|
}
|
|
53
49
|
};
|
|
54
50
|
const step = fieldType === "int" || fieldType === "bigint" ? "1" : "any";
|
|
55
|
-
return /* @__PURE__ */
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
} }, minValue && maxValue && `${minValue} to ${maxValue}`, minValue && !maxValue && `≥ ${minValue}`, !minValue && maxValue && `≤ ${maxValue}`));
|
|
51
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
52
|
+
/* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700", children: formatFieldName(fieldName) }),
|
|
53
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
54
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
55
|
+
/* @__PURE__ */ jsx("label", { htmlFor: `${fieldName}-min`, className: "block text-xs text-gray-500 mb-1", children: "Min" }),
|
|
56
|
+
/* @__PURE__ */ jsx(
|
|
57
|
+
"input",
|
|
58
|
+
{
|
|
59
|
+
id: `${fieldName}-min`,
|
|
60
|
+
type: "number",
|
|
61
|
+
step,
|
|
62
|
+
value: minValue,
|
|
63
|
+
onChange: (e) => handleMinChange(e.target.value),
|
|
64
|
+
placeholder: "No minimum",
|
|
65
|
+
className: "w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-1 focus:ring-green-web focus:border-green-web"
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
] }),
|
|
69
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
70
|
+
/* @__PURE__ */ jsx("label", { htmlFor: `${fieldName}-max`, className: "block text-xs text-gray-500 mb-1", children: "Max" }),
|
|
71
|
+
/* @__PURE__ */ jsx(
|
|
72
|
+
"input",
|
|
73
|
+
{
|
|
74
|
+
id: `${fieldName}-max`,
|
|
75
|
+
type: "number",
|
|
76
|
+
step,
|
|
77
|
+
value: maxValue,
|
|
78
|
+
onChange: (e) => handleMaxChange(e.target.value),
|
|
79
|
+
placeholder: "No maximum",
|
|
80
|
+
className: "w-full px-2 py-1 text-sm border border-gray-300 rounded-md focus:outline-none focus:ring-1 focus:ring-green-web focus:border-green-web"
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
] })
|
|
84
|
+
] }),
|
|
85
|
+
(minValue || maxValue) && /* @__PURE__ */ jsxs("div", { className: "text-xs text-gray-500", children: [
|
|
86
|
+
minValue && maxValue && `${minValue} to ${maxValue}`,
|
|
87
|
+
minValue && !maxValue && `≥ ${minValue}`,
|
|
88
|
+
!minValue && maxValue && `≤ ${maxValue}`
|
|
89
|
+
] })
|
|
90
|
+
] });
|
|
96
91
|
}
|
|
97
92
|
export {
|
|
98
93
|
NumberRangeFilter
|
|
@@ -1,53 +1,63 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
1
2
|
import { getItemDisplayName } from "../../utils/string-utils.js";
|
|
2
|
-
var _jsxFileName = "/Users/justinhandley/IdeaProjects/nestled_template/libs/data-browser/src/lib/components/filters/RelationComponents.tsx";
|
|
3
3
|
function RelationDropdownButton({
|
|
4
4
|
currentItem,
|
|
5
5
|
relatedModelName,
|
|
6
6
|
isOpen,
|
|
7
7
|
onClick
|
|
8
8
|
}) {
|
|
9
|
-
return /* @__PURE__ */
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
9
|
+
return /* @__PURE__ */ jsxs(
|
|
10
|
+
"button",
|
|
11
|
+
{
|
|
12
|
+
type: "button",
|
|
13
|
+
onClick,
|
|
14
|
+
className: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-web focus:border-green-web text-sm text-left bg-white flex items-center justify-between",
|
|
15
|
+
children: [
|
|
16
|
+
/* @__PURE__ */ jsx("span", { className: currentItem ? "text-gray-900" : "text-gray-500", children: currentItem ? getItemDisplayName(currentItem) : `Select ${relatedModelName.toLowerCase()}...` }),
|
|
17
|
+
/* @__PURE__ */ jsx(
|
|
18
|
+
"svg",
|
|
19
|
+
{
|
|
20
|
+
className: `w-4 h-4 text-gray-400 transition-transform ${isOpen ? "rotate-180" : ""}`,
|
|
21
|
+
fill: "none",
|
|
22
|
+
stroke: "currentColor",
|
|
23
|
+
viewBox: "0 0 24 24",
|
|
24
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" })
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
);
|
|
26
30
|
}
|
|
27
31
|
function RelationSearchInput({
|
|
28
32
|
searchTerm,
|
|
29
33
|
onSearchChange,
|
|
30
34
|
relatedModelName
|
|
31
35
|
}) {
|
|
32
|
-
return /* @__PURE__ */
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
return /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
|
|
37
|
+
"input",
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
placeholder: `Search ${relatedModelName.toLowerCase()}...`,
|
|
41
|
+
value: searchTerm,
|
|
42
|
+
onChange: (e) => onSearchChange(e.target.value),
|
|
43
|
+
className: "w-full px-2 py-1 text-sm border border-gray-300 rounded focus:outline-none focus:ring-1 focus:ring-green-web",
|
|
44
|
+
autoFocus: true
|
|
45
|
+
}
|
|
46
|
+
) });
|
|
41
47
|
}
|
|
42
48
|
function RelationItem({
|
|
43
49
|
item,
|
|
44
50
|
onSelect
|
|
45
51
|
}) {
|
|
46
|
-
return /* @__PURE__ */
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
return /* @__PURE__ */ jsx(
|
|
53
|
+
"button",
|
|
54
|
+
{
|
|
55
|
+
type: "button",
|
|
56
|
+
onClick: () => onSelect(item),
|
|
57
|
+
className: "w-full px-3 py-2 text-left text-sm hover:bg-gray-100 focus:bg-gray-100 transition-colors",
|
|
58
|
+
children: getItemDisplayName(item)
|
|
59
|
+
}
|
|
60
|
+
);
|
|
51
61
|
}
|
|
52
62
|
function RelationItemList({
|
|
53
63
|
items,
|
|
@@ -56,63 +66,40 @@ function RelationItemList({
|
|
|
56
66
|
onSelect,
|
|
57
67
|
onClear
|
|
58
68
|
}) {
|
|
59
|
-
return /* @__PURE__ */
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
lineNumber: 118,
|
|
94
|
-
columnNumber: 11
|
|
95
|
-
} }, /* @__PURE__ */ React.createElement("svg", { className: "animate-spin -ml-1 mr-2 h-4 w-4 text-gray-500", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", __self: this, __source: {
|
|
96
|
-
fileName: _jsxFileName,
|
|
97
|
-
lineNumber: 119,
|
|
98
|
-
columnNumber: 13
|
|
99
|
-
} }, /* @__PURE__ */ React.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4", __self: this, __source: {
|
|
100
|
-
fileName: _jsxFileName,
|
|
101
|
-
lineNumber: 120,
|
|
102
|
-
columnNumber: 15
|
|
103
|
-
} }), /* @__PURE__ */ React.createElement("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z", __self: this, __source: {
|
|
104
|
-
fileName: _jsxFileName,
|
|
105
|
-
lineNumber: 121,
|
|
106
|
-
columnNumber: 15
|
|
107
|
-
} })), "Loading...")), !error && !loading && items.length === 0 && /* @__PURE__ */ React.createElement("div", { className: "px-3 py-2 text-sm text-gray-500", __self: this, __source: {
|
|
108
|
-
fileName: _jsxFileName,
|
|
109
|
-
lineNumber: 128,
|
|
110
|
-
columnNumber: 9
|
|
111
|
-
} }, "No items found"), !error && !loading && items.length > 0 && items.map((item) => /* @__PURE__ */ React.createElement(RelationItem, { key: item.id, item, onSelect, __self: this, __source: {
|
|
112
|
-
fileName: _jsxFileName,
|
|
113
|
-
lineNumber: 132,
|
|
114
|
-
columnNumber: 11
|
|
115
|
-
} })));
|
|
69
|
+
return /* @__PURE__ */ jsxs("div", { className: "max-h-48 overflow-y-auto", children: [
|
|
70
|
+
/* @__PURE__ */ jsx(
|
|
71
|
+
"button",
|
|
72
|
+
{
|
|
73
|
+
type: "button",
|
|
74
|
+
onClick: onClear,
|
|
75
|
+
className: "w-full px-3 py-2 text-left text-sm hover:bg-gray-100 text-gray-500 border-b border-gray-200",
|
|
76
|
+
children: "Clear selection"
|
|
77
|
+
}
|
|
78
|
+
),
|
|
79
|
+
error && /* @__PURE__ */ jsxs("div", { className: "px-3 py-2 text-sm text-red-600", children: [
|
|
80
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
|
81
|
+
/* @__PURE__ */ jsx("svg", { className: "w-4 h-4 mr-2", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
|
|
82
|
+
"Failed to load options"
|
|
83
|
+
] }),
|
|
84
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500 mt-1", children: error.networkError ? "Network error" : "Please try again" })
|
|
85
|
+
] }),
|
|
86
|
+
!error && loading && /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-sm text-gray-500", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
|
|
87
|
+
/* @__PURE__ */ jsxs("svg", { className: "animate-spin -ml-1 mr-2 h-4 w-4 text-gray-500", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [
|
|
88
|
+
/* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
89
|
+
/* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })
|
|
90
|
+
] }),
|
|
91
|
+
"Loading..."
|
|
92
|
+
] }) }),
|
|
93
|
+
!error && !loading && items.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-3 py-2 text-sm text-gray-500", children: "No items found" }),
|
|
94
|
+
!error && !loading && items.length > 0 && items.map((item) => /* @__PURE__ */ jsx(
|
|
95
|
+
RelationItem,
|
|
96
|
+
{
|
|
97
|
+
item,
|
|
98
|
+
onSelect
|
|
99
|
+
},
|
|
100
|
+
item.id
|
|
101
|
+
))
|
|
102
|
+
] });
|
|
116
103
|
}
|
|
117
104
|
function RelationDropdownContent({
|
|
118
105
|
searchTerm,
|
|
@@ -124,19 +111,26 @@ function RelationDropdownContent({
|
|
|
124
111
|
onSelect,
|
|
125
112
|
onClear
|
|
126
113
|
}) {
|
|
127
|
-
return /* @__PURE__ */
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
114
|
+
return /* @__PURE__ */ jsxs("div", { className: "absolute z-10 w-full mt-1 bg-white border border-gray-300 rounded-md shadow-lg", children: [
|
|
115
|
+
/* @__PURE__ */ jsx(
|
|
116
|
+
RelationSearchInput,
|
|
117
|
+
{
|
|
118
|
+
searchTerm,
|
|
119
|
+
onSearchChange,
|
|
120
|
+
relatedModelName
|
|
121
|
+
}
|
|
122
|
+
),
|
|
123
|
+
/* @__PURE__ */ jsx(
|
|
124
|
+
RelationItemList,
|
|
125
|
+
{
|
|
126
|
+
items,
|
|
127
|
+
loading,
|
|
128
|
+
error,
|
|
129
|
+
onSelect,
|
|
130
|
+
onClear
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
] });
|
|
140
134
|
}
|
|
141
135
|
export {
|
|
142
136
|
RelationDropdownButton,
|