@rulab/adminjs-components 0.1.0-alpha.8 → 0.1.0-beta.1
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/components/ColorStatus/ColorStatusEdit.d.ts +2 -2
- package/dist/components/ColorStatus/ColorStatusEdit.js +3 -3
- package/dist/components/ColorStatus/ColorStatusFeature.d.ts +9 -0
- package/dist/components/ColorStatus/ColorStatusFeature.js +23 -0
- package/dist/components/ColorStatus/ColorStatusList.d.ts +1 -1
- package/dist/components/ColorStatus/ColorStatusList.js +4 -2
- package/dist/components/ColorStatus/ColorStatusShow.d.ts +1 -1
- package/dist/components/ColorStatus/ColorStatusShow.js +5 -3
- package/dist/components/ColorStatus/index.d.ts +4 -3
- package/dist/components/ColorStatus/index.js +4 -3
- package/dist/components/ColorStatus/styles.js +2 -1
- package/dist/components/Editor/Editor.d.ts +4 -2
- package/dist/components/Editor/Editor.js +79 -16
- package/dist/components/Editor/EditorFeature.d.ts +10 -0
- package/dist/components/Editor/EditorFeature.js +82 -0
- package/dist/components/Editor/EditorList.d.ts +2 -2
- package/dist/components/Editor/EditorList.js +1 -1
- package/dist/components/Editor/EditorShow.d.ts +2 -2
- package/dist/components/Editor/EditorShow.js +2 -2
- package/dist/components/Editor/index.d.ts +4 -3
- package/dist/components/Editor/index.js +4 -3
- package/dist/components/FeatureTabs/FeatureTabsEdit.d.ts +4 -0
- package/dist/components/FeatureTabs/FeatureTabsEdit.js +105 -0
- package/dist/components/FeatureTabs/FeatureTabsFeature.d.ts +8 -0
- package/dist/components/FeatureTabs/FeatureTabsFeature.js +28 -0
- package/dist/components/FeatureTabs/FeatureTabsShow.d.ts +4 -0
- package/dist/components/FeatureTabs/FeatureTabsShow.js +61 -0
- package/dist/components/FeatureTabs/index.d.ts +4 -0
- package/dist/components/FeatureTabs/index.js +4 -0
- package/dist/components/Preview/PreviewAction.d.ts +4 -0
- package/dist/components/Preview/PreviewAction.js +22 -0
- package/dist/components/Preview/PreviewFeature.d.ts +9 -0
- package/dist/components/Preview/PreviewFeature.js +31 -0
- package/dist/components/Preview/index.d.ts +2 -0
- package/dist/components/Preview/index.js +2 -0
- package/dist/components/Slug/SlugEdit.d.ts +1 -1
- package/dist/components/Slug/SlugEdit.js +9 -3
- package/dist/components/Slug/SlugFeature.d.ts +3 -6
- package/dist/components/Slug/SlugFeature.js +12 -14
- package/dist/components/Slug/SlugOptions.type.d.ts +7 -0
- package/dist/components/StringList/StringList.d.ts +1 -1
- package/dist/components/StringList/StringList.js +4 -4
- package/dist/components/StringList/StringListFeature.d.ts +7 -0
- package/dist/components/StringList/StringListFeature.js +20 -0
- package/dist/components/StringList/StringListShow.d.ts +1 -1
- package/dist/components/StringList/StringListShow.js +2 -2
- package/dist/components/StringList/index.d.ts +3 -2
- package/dist/components/StringList/index.js +3 -2
- package/dist/components/StringList/styles.js +2 -1
- package/dist/components/Tabs/TabsEdit.d.ts +4 -0
- package/dist/components/Tabs/TabsEdit.js +103 -0
- package/dist/components/Tabs/TabsFeature.d.ts +7 -0
- package/dist/components/Tabs/TabsFeature.js +26 -0
- package/dist/components/Tabs/TabsShow.d.ts +4 -0
- package/dist/components/Tabs/TabsShow.js +61 -0
- package/dist/components/Tabs/index.d.ts +3 -0
- package/dist/components/Tabs/index.js +3 -0
- package/dist/components/index.d.ts +15 -7
- package/dist/components/index.js +15 -10
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types/upload-provider.d.ts +13 -0
- package/dist/utils/bundle-component.d.ts +1 -1
- package/dist/utils/bundle-component.js +5 -8
- package/dist/utils/component-loader.d.ts +3 -0
- package/dist/utils/component-loader.js +10 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +12 -11
- package/src/components/ColorStatus/ColorStatusEdit.d.ts +0 -5
- package/src/components/ColorStatus/ColorStatusEdit.js +0 -58
- package/src/components/ColorStatus/ColorStatusEdit.tsx +0 -94
- package/src/components/ColorStatus/ColorStatusList.d.ts +0 -4
- package/src/components/ColorStatus/ColorStatusList.js +0 -7
- package/src/components/ColorStatus/ColorStatusList.tsx +0 -20
- package/src/components/ColorStatus/ColorStatusShow.d.ts +0 -4
- package/src/components/ColorStatus/ColorStatusShow.js +0 -9
- package/src/components/ColorStatus/ColorStatusShow.tsx +0 -23
- package/src/components/ColorStatus/index.d.ts +0 -3
- package/src/components/ColorStatus/index.js +0 -3
- package/src/components/ColorStatus/index.ts +0 -3
- package/src/components/ColorStatus/styles.d.ts +0 -5
- package/src/components/ColorStatus/styles.js +0 -25
- package/src/components/ColorStatus/styles.ts +0 -30
- package/src/components/ColorStatus/types.d.ts +0 -5
- package/src/components/ColorStatus/types.ts +0 -5
- package/src/components/Editor/Editor.d.ts +0 -8
- package/src/components/Editor/Editor.js +0 -36
- package/src/components/Editor/Editor.jsx +0 -49
- package/src/components/Editor/EditorList.d.ts +0 -6
- package/src/components/Editor/EditorList.js +0 -11
- package/src/components/Editor/EditorList.jsx +0 -22
- package/src/components/Editor/EditorShow.d.ts +0 -6
- package/src/components/Editor/EditorShow.js +0 -13
- package/src/components/Editor/EditorShow.jsx +0 -24
- package/src/components/Editor/config.d.ts +0 -29
- package/src/components/Editor/config.js +0 -34
- package/src/components/Editor/config.ts +0 -35
- package/src/components/Editor/index.d.ts +0 -3
- package/src/components/Editor/index.js +0 -3
- package/src/components/Editor/index.ts +0 -3
- package/src/components/Editor/styles.d.ts +0 -6
- package/src/components/Editor/styles.js +0 -145
- package/src/components/Editor/styles.ts +0 -151
- package/src/components/Slug/SlugEdit.d.ts +0 -5
- package/src/components/Slug/SlugEdit.js +0 -27
- package/src/components/Slug/SlugEdit.tsx +0 -68
- package/src/components/Slug/SlugFeature.d.ts +0 -7
- package/src/components/Slug/SlugFeature.js +0 -21
- package/src/components/Slug/SlugFeature.ts +0 -30
- package/src/components/Slug/index.d.ts +0 -1
- package/src/components/Slug/index.js +0 -1
- package/src/components/Slug/index.ts +0 -1
- package/src/components/Slug/styles.d.ts +0 -4
- package/src/components/Slug/styles.js +0 -20
- package/src/components/Slug/styles.ts +0 -24
- package/src/components/StringList/SortableList/SortableList.d.ts +0 -18
- package/src/components/StringList/SortableList/SortableList.js +0 -37
- package/src/components/StringList/SortableList/SortableList.tsx +0 -98
- package/src/components/StringList/SortableList/components/SortableItem/DragHandle.d.ts +0 -7
- package/src/components/StringList/SortableList/components/SortableItem/DragHandle.js +0 -8
- package/src/components/StringList/SortableList/components/SortableItem/DragHandle.tsx +0 -20
- package/src/components/StringList/SortableList/components/SortableItem/SortableItem.d.ts +0 -8
- package/src/components/StringList/SortableList/components/SortableItem/SortableItem.js +0 -28
- package/src/components/StringList/SortableList/components/SortableItem/SortableItem.tsx +0 -59
- package/src/components/StringList/SortableList/components/SortableItem/styles.d.ts +0 -2
- package/src/components/StringList/SortableList/components/SortableItem/styles.js +0 -20
- package/src/components/StringList/SortableList/components/SortableItem/styles.ts +0 -22
- package/src/components/StringList/SortableList/components/SortableItem/types.d.ts +0 -6
- package/src/components/StringList/SortableList/components/SortableItem/types.ts +0 -7
- package/src/components/StringList/SortableList/components/index.d.ts +0 -2
- package/src/components/StringList/SortableList/components/index.js +0 -2
- package/src/components/StringList/SortableList/components/index.ts +0 -2
- package/src/components/StringList/SortableList/index.d.ts +0 -1
- package/src/components/StringList/SortableList/index.js +0 -1
- package/src/components/StringList/SortableList/index.ts +0 -1
- package/src/components/StringList/SortableList/styles.d.ts +0 -1
- package/src/components/StringList/SortableList/styles.js +0 -8
- package/src/components/StringList/SortableList/styles.ts +0 -9
- package/src/components/StringList/StringList.d.ts +0 -8
- package/src/components/StringList/StringList.js +0 -60
- package/src/components/StringList/StringList.tsx +0 -136
- package/src/components/StringList/StringListShow.d.ts +0 -7
- package/src/components/StringList/StringListShow.js +0 -14
- package/src/components/StringList/StringListShow.tsx +0 -37
- package/src/components/StringList/constants.d.ts +0 -1
- package/src/components/StringList/constants.js +0 -1
- package/src/components/StringList/constants.ts +0 -1
- package/src/components/StringList/index.d.ts +0 -2
- package/src/components/StringList/index.js +0 -2
- package/src/components/StringList/index.ts +0 -2
- package/src/components/StringList/styles.d.ts +0 -8
- package/src/components/StringList/styles.js +0 -33
- package/src/components/StringList/styles.ts +0 -41
- package/src/components/index.d.ts +0 -7
- package/src/components/index.js +0 -10
- package/src/components/index.ts +0 -10
- /package/{src/components/ColorStatus/types.js → dist/components/Slug/SlugOptions.type.js} +0 -0
- /package/{src/components/StringList/SortableList/components/SortableItem/types.js → dist/types/upload-provider.js} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FC } from "react";
|
|
2
2
|
import { EditPropertyProps } from "adminjs";
|
|
3
3
|
type ColorStatusTypes = Omit<EditPropertyProps, "where" | "resource">;
|
|
4
|
-
declare const
|
|
5
|
-
export default
|
|
4
|
+
export declare const ColorStatusEdit: FC<ColorStatusTypes>;
|
|
5
|
+
export default ColorStatusEdit;
|
|
@@ -41,7 +41,7 @@ const colorStyles = {
|
|
|
41
41
|
placeholder: (styles) => ({ ...styles, ...dot("#ccc") }),
|
|
42
42
|
singleValue: (styles, { data }) => ({ ...styles, ...dot(data.color) }),
|
|
43
43
|
};
|
|
44
|
-
const
|
|
44
|
+
export const ColorStatusEdit = ({ property, record, onChange, }) => {
|
|
45
45
|
const availableValues = property.availableValues;
|
|
46
46
|
const currentOption = availableValues.find((item) => item.value === record.params[property.path]);
|
|
47
47
|
const [selectOption, setCurrentOption] = useState(currentOption);
|
|
@@ -52,7 +52,7 @@ const ColorStatus = ({ property, record, onChange }) => {
|
|
|
52
52
|
onChange(property.path, selectOption?.value);
|
|
53
53
|
}, [selectOption]);
|
|
54
54
|
return (React.createElement(ColorStatusWrapper, null,
|
|
55
|
-
React.createElement(Label, null, property.path),
|
|
55
|
+
React.createElement(Label, null, property.label ?? property.path),
|
|
56
56
|
React.createElement(Select, { className: "basic-single", classNamePrefix: "select", defaultValue: selectOption ?? availableValues[0], onChange: handleSelectChange, isClearable: true, name: "color", options: availableValues, styles: colorStyles })));
|
|
57
57
|
};
|
|
58
|
-
export default
|
|
58
|
+
export default ColorStatusEdit;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ComponentLoader, FeatureType } from "adminjs";
|
|
2
|
+
import type { AvailableValueType } from "./types.js";
|
|
3
|
+
type ColorStatusOptions = {
|
|
4
|
+
componentLoader?: ComponentLoader;
|
|
5
|
+
key: string;
|
|
6
|
+
availableValues?: AvailableValueType[];
|
|
7
|
+
};
|
|
8
|
+
export declare const ColorStatusFeature: (config: ColorStatusOptions) => FeatureType;
|
|
9
|
+
export default ColorStatusFeature;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { buildFeature } from "adminjs";
|
|
2
|
+
import { bundleComponent } from "../../utils/bundle-component.js";
|
|
3
|
+
const COMPONENT_NAME = "ColorStatus";
|
|
4
|
+
export const ColorStatusFeature = (config) => {
|
|
5
|
+
const { componentLoader, key, availableValues = [] } = config;
|
|
6
|
+
const editComponent = bundleComponent(componentLoader, COMPONENT_NAME, "ColorStatusEdit.js");
|
|
7
|
+
const listComponent = bundleComponent(componentLoader, COMPONENT_NAME, "ColorStatusList.js");
|
|
8
|
+
const showComponent = bundleComponent(componentLoader, COMPONENT_NAME, "ColorStatusShow.js");
|
|
9
|
+
return buildFeature({
|
|
10
|
+
properties: {
|
|
11
|
+
[key]: {
|
|
12
|
+
isVisible: { filter: true, show: true, edit: true, list: true },
|
|
13
|
+
availableValues,
|
|
14
|
+
components: {
|
|
15
|
+
edit: editComponent,
|
|
16
|
+
list: listComponent,
|
|
17
|
+
show: showComponent,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
export default ColorStatusFeature;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { ColorStatusBadge } from "./styles.js";
|
|
3
|
-
const ColorStatusList = ({ property, record }) => {
|
|
3
|
+
export const ColorStatusList = ({ property, record }) => {
|
|
4
4
|
const currentOption = property.availableValues?.find((item) => item.value === record.params[property.path]);
|
|
5
|
-
|
|
5
|
+
const currentValue = record.params[property.path];
|
|
6
|
+
const displayValue = currentOption?.label ?? currentValue;
|
|
7
|
+
return (React.createElement(ColorStatusBadge, { color: currentOption?.color }, displayValue));
|
|
6
8
|
};
|
|
7
9
|
export default ColorStatusList;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { ColorStatusBadgeWrapper, ColorStatusBadge, ShowLabel } from "./styles.js";
|
|
3
|
-
const ColorStatusShow = ({ property, record }) => {
|
|
3
|
+
export const ColorStatusShow = ({ property, record }) => {
|
|
4
4
|
const currentOption = property.availableValues?.find((item) => item.value === record.params[property.path]);
|
|
5
|
+
const currentValue = record.params[property.path];
|
|
6
|
+
const displayValue = currentOption?.label ?? currentValue;
|
|
5
7
|
return (React.createElement(ColorStatusBadgeWrapper, null,
|
|
6
|
-
React.createElement(ShowLabel, null, property.path),
|
|
7
|
-
React.createElement(ColorStatusBadge, { color: currentOption
|
|
8
|
+
React.createElement(ShowLabel, null, property.label ?? property.path),
|
|
9
|
+
React.createElement(ColorStatusBadge, { color: currentOption?.color }, displayValue)));
|
|
8
10
|
};
|
|
9
11
|
export default ColorStatusShow;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
1
|
+
export { ColorStatusEdit } from "./ColorStatusEdit.js";
|
|
2
|
+
export { ColorStatusShow } from "./ColorStatusShow.js";
|
|
3
|
+
export { ColorStatusList } from "./ColorStatusList.js";
|
|
4
|
+
export { ColorStatusFeature } from "./ColorStatusFeature.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
1
|
+
export { ColorStatusEdit } from "./ColorStatusEdit.js";
|
|
2
|
+
export { ColorStatusShow } from "./ColorStatusShow.js";
|
|
3
|
+
export { ColorStatusList } from "./ColorStatusList.js";
|
|
4
|
+
export { ColorStatusFeature } from "./ColorStatusFeature.js";
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { styled } from "@adminjs/design-system/styled-components";
|
|
2
2
|
export const ColorStatusWrapper = styled.div `
|
|
3
|
-
margin-bottom:
|
|
3
|
+
margin-bottom: 45px;
|
|
4
4
|
`;
|
|
5
5
|
export const Label = styled.div `
|
|
6
6
|
font-size: 12px;
|
|
7
7
|
margin-bottom: 8px;
|
|
8
|
+
text-transform: capitalize;
|
|
8
9
|
`;
|
|
9
10
|
export const ShowLabel = styled.div `
|
|
10
11
|
font-size: 12px;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
export
|
|
2
|
-
declare function Editor({ property, record, onChangeAdmin, editorId }: {
|
|
1
|
+
export function Editor({ property, record, resource, onChange, onChangeAdmin, editorId }: {
|
|
3
2
|
property: any;
|
|
4
3
|
record: any;
|
|
4
|
+
resource: any;
|
|
5
|
+
onChange: any;
|
|
5
6
|
onChangeAdmin: any;
|
|
6
7
|
editorId: any;
|
|
7
8
|
}): React.FunctionComponentElement<{
|
|
8
9
|
children?: React.ReactNode;
|
|
9
10
|
theme: import("styled-components").DefaultTheme | ((outerTheme?: import("styled-components").DefaultTheme | undefined) => import("styled-components").DefaultTheme);
|
|
10
11
|
}>;
|
|
12
|
+
export default Editor;
|
|
11
13
|
import React from "react";
|
|
@@ -1,33 +1,96 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useState, useEffect, useRef } from "react";
|
|
2
2
|
import { ThemeProvider } from "styled-components";
|
|
3
|
-
import EditorJS from "@editorjs/editorjs";
|
|
4
3
|
import { theme } from "@adminjs/design-system";
|
|
4
|
+
import { ApiClient } from "adminjs";
|
|
5
5
|
import { StyledLabel, StyledEditor, StyledEditorWrapper } from "./styles.js";
|
|
6
6
|
import { EDITOR_TOOLS } from "./config.js";
|
|
7
|
-
const
|
|
7
|
+
const readFileAsBase64 = (file) => new Promise((resolve, reject) => {
|
|
8
|
+
const reader = new FileReader();
|
|
9
|
+
reader.onload = () => {
|
|
10
|
+
const result = reader.result ?? "";
|
|
11
|
+
const base64 = String(result).split(",")[1] ?? "";
|
|
12
|
+
resolve(base64);
|
|
13
|
+
};
|
|
14
|
+
reader.onerror = reject;
|
|
15
|
+
reader.readAsDataURL(file);
|
|
16
|
+
});
|
|
17
|
+
const getEditorData = (record, property) => {
|
|
18
|
+
const raw = record?.params?.[property.path];
|
|
19
|
+
if (!raw) {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(raw);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
return "";
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
export const Editor = ({ property, record, resource, onChange, onChangeAdmin, editorId }) => {
|
|
8
30
|
const [jsonData, setJsonData] = useState();
|
|
9
|
-
const isSavedData = Boolean(record
|
|
31
|
+
const isSavedData = Boolean(record?.params?.[property.path]);
|
|
32
|
+
const holderId = editorId || property?.props?.editorId || `editor-${property.path}`;
|
|
33
|
+
const uploadAction = property?.props?.uploadAction;
|
|
34
|
+
const resourceId = resource?.id;
|
|
10
35
|
const ref = useRef();
|
|
11
36
|
useEffect(() => {
|
|
12
|
-
onChangeAdmin
|
|
37
|
+
const changeHandler = onChange ?? onChangeAdmin;
|
|
38
|
+
if (changeHandler) {
|
|
39
|
+
changeHandler(property.path, jsonData);
|
|
40
|
+
}
|
|
13
41
|
}, [jsonData]);
|
|
14
42
|
useEffect(() => {
|
|
15
43
|
if (!ref.current) {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
tools
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
44
|
+
const init = async () => {
|
|
45
|
+
const { default: EditorJS } = await import("@editorjs/editorjs");
|
|
46
|
+
const tools = { ...EDITOR_TOOLS };
|
|
47
|
+
if (uploadAction && resourceId) {
|
|
48
|
+
const { default: ImageTool } = await import("@editorjs/image");
|
|
49
|
+
const api = new ApiClient();
|
|
50
|
+
tools.image = {
|
|
51
|
+
class: ImageTool,
|
|
52
|
+
config: {
|
|
53
|
+
uploader: {
|
|
54
|
+
uploadByFile: async (file) => {
|
|
55
|
+
const base64 = await readFileAsBase64(file);
|
|
56
|
+
const response = await api.resourceAction({
|
|
57
|
+
resourceId,
|
|
58
|
+
actionName: uploadAction,
|
|
59
|
+
data: {
|
|
60
|
+
file: {
|
|
61
|
+
name: file.name,
|
|
62
|
+
type: file.type,
|
|
63
|
+
base64,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
const url = response?.data?.data?.url;
|
|
68
|
+
if (!url) {
|
|
69
|
+
return { success: 0 };
|
|
70
|
+
}
|
|
71
|
+
return { success: 1, file: { url } };
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const editor = new EditorJS({
|
|
78
|
+
holder: holderId,
|
|
79
|
+
tools,
|
|
80
|
+
data: isSavedData ? getEditorData(record, property) : "",
|
|
81
|
+
async onChange(api, event) {
|
|
82
|
+
const data = await api.saver.save();
|
|
83
|
+
setJsonData(JSON.stringify(data));
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
ref.current = editor;
|
|
87
|
+
};
|
|
88
|
+
void init();
|
|
26
89
|
}
|
|
27
90
|
return () => {
|
|
28
91
|
ref?.current?.destroy?.();
|
|
29
92
|
};
|
|
30
93
|
}, []);
|
|
31
|
-
return (React.createElement(ThemeProvider, { theme: theme }, React.createElement(StyledLabel, null, property.path), React.createElement(StyledEditorWrapper, null, React.createElement(StyledEditor, { id:
|
|
94
|
+
return (React.createElement(ThemeProvider, { theme: theme }, React.createElement(StyledLabel, null, property.label ?? property.path), React.createElement(StyledEditorWrapper, null, React.createElement(StyledEditor, { id: holderId }))));
|
|
32
95
|
};
|
|
33
96
|
export default Editor;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ComponentLoader, FeatureType } from "adminjs";
|
|
2
|
+
import type { BaseProvider } from "@adminjs/upload";
|
|
3
|
+
type EditorOptions = {
|
|
4
|
+
componentLoader?: ComponentLoader;
|
|
5
|
+
key: string;
|
|
6
|
+
uploadProvider?: BaseProvider;
|
|
7
|
+
uploadActionName?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const EditorFeature: (config: EditorOptions) => FeatureType;
|
|
10
|
+
export default EditorFeature;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { buildFeature } from "adminjs";
|
|
2
|
+
import { Buffer } from "node:buffer";
|
|
3
|
+
import { promises as fs } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { bundleComponent } from "../../utils/bundle-component.js";
|
|
7
|
+
import { slugifyTitle } from "../../utils/slugifyTitle.js";
|
|
8
|
+
const COMPONENT_NAME = "Editor";
|
|
9
|
+
export const EditorFeature = (config) => {
|
|
10
|
+
const { componentLoader, key, uploadProvider } = config;
|
|
11
|
+
const uploadActionName = config.uploadActionName ?? "editorUpload";
|
|
12
|
+
const editComponent = bundleComponent(componentLoader, COMPONENT_NAME, "Editor.js");
|
|
13
|
+
const listComponent = bundleComponent(componentLoader, COMPONENT_NAME, "EditorList.js");
|
|
14
|
+
const showComponent = bundleComponent(componentLoader, COMPONENT_NAME, "EditorShow.js");
|
|
15
|
+
return buildFeature({
|
|
16
|
+
actions: uploadProvider
|
|
17
|
+
? {
|
|
18
|
+
[uploadActionName]: {
|
|
19
|
+
actionType: "resource",
|
|
20
|
+
isVisible: false,
|
|
21
|
+
handler: async (request, _response, context) => {
|
|
22
|
+
const file = request?.payload?.file;
|
|
23
|
+
if (!file?.base64) {
|
|
24
|
+
return {
|
|
25
|
+
data: { error: "No file provided." },
|
|
26
|
+
notice: { message: "No file provided.", type: "error" },
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const buffer = Buffer.from(file.base64, "base64");
|
|
30
|
+
const originalName = file.name ?? "upload";
|
|
31
|
+
const filename = slugifyFilename(originalName);
|
|
32
|
+
const key = `${Date.now()}-${filename}`;
|
|
33
|
+
const tempPath = join(tmpdir(), `${Date.now()}-${filename}`);
|
|
34
|
+
const uploadedFile = {
|
|
35
|
+
name: filename,
|
|
36
|
+
type: file.type ?? "application/octet-stream",
|
|
37
|
+
size: buffer.length,
|
|
38
|
+
path: tempPath,
|
|
39
|
+
};
|
|
40
|
+
await fs.writeFile(tempPath, buffer);
|
|
41
|
+
try {
|
|
42
|
+
await uploadProvider.upload(uploadedFile, key, context);
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
await fs.unlink(tempPath).catch(() => undefined);
|
|
46
|
+
}
|
|
47
|
+
const baseUrl = uploadProvider.opts?.baseUrl;
|
|
48
|
+
const url = baseUrl
|
|
49
|
+
? `${baseUrl.replace(/\/$/, "")}/${key}`
|
|
50
|
+
: await uploadProvider.path(key, uploadProvider.bucket, context);
|
|
51
|
+
if (!url) {
|
|
52
|
+
return {
|
|
53
|
+
data: { error: "Upload failed." },
|
|
54
|
+
notice: { message: "Upload failed.", type: "error" },
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return { data: { url } };
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
: undefined,
|
|
62
|
+
properties: {
|
|
63
|
+
[key]: {
|
|
64
|
+
isVisible: { filter: true, show: true, edit: true, list: true },
|
|
65
|
+
props: uploadProvider ? { uploadAction: uploadActionName } : undefined,
|
|
66
|
+
components: {
|
|
67
|
+
edit: editComponent,
|
|
68
|
+
list: listComponent,
|
|
69
|
+
show: showComponent,
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
const slugifyFilename = (name) => {
|
|
76
|
+
const lastDot = name.lastIndexOf(".");
|
|
77
|
+
const base = lastDot > 0 ? name.slice(0, lastDot) : name;
|
|
78
|
+
const ext = lastDot > 0 ? name.slice(lastDot) : "";
|
|
79
|
+
const slug = slugifyTitle(base) || "file";
|
|
80
|
+
return `${slug}${ext}`;
|
|
81
|
+
};
|
|
82
|
+
export default EditorFeature;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export
|
|
2
|
-
declare function EditorList({ property, record }: {
|
|
1
|
+
export function EditorList({ property, record }: {
|
|
3
2
|
property: any;
|
|
4
3
|
record: any;
|
|
5
4
|
}): React.FunctionComponentElement<{
|
|
6
5
|
children?: React.ReactNode;
|
|
7
6
|
theme: import("styled-components").DefaultTheme | ((outerTheme?: import("styled-components").DefaultTheme | undefined) => import("styled-components").DefaultTheme);
|
|
8
7
|
}>;
|
|
8
|
+
export default EditorList;
|
|
9
9
|
import React from "react";
|
|
@@ -3,7 +3,7 @@ import { theme } from "@adminjs/design-system";
|
|
|
3
3
|
import { ThemeProvider } from "styled-components";
|
|
4
4
|
import { parseHtml } from "../../utils/parseHtml.js";
|
|
5
5
|
import { StyledEditorViewWrapper } from "./styles.js";
|
|
6
|
-
const EditorList = ({ property, record }) => {
|
|
6
|
+
export const EditorList = ({ property, record }) => {
|
|
7
7
|
const htmlContent = parseHtml(record.params[property.path]);
|
|
8
8
|
return (React.createElement(ThemeProvider, { theme: theme }, React.createElement(StyledEditorViewWrapper, null, htmlContent && (React.createElement("div", { dangerouslySetInnerHTML: { __html: htmlContent } })))));
|
|
9
9
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export
|
|
2
|
-
declare function EditorShow({ property, record }: {
|
|
1
|
+
export function EditorShow({ property, record }: {
|
|
3
2
|
property: any;
|
|
4
3
|
record: any;
|
|
5
4
|
}): React.FunctionComponentElement<{
|
|
6
5
|
children?: React.ReactNode;
|
|
7
6
|
theme: import("styled-components").DefaultTheme | ((outerTheme?: import("styled-components").DefaultTheme | undefined) => import("styled-components").DefaultTheme);
|
|
8
7
|
}>;
|
|
8
|
+
export default EditorShow;
|
|
9
9
|
import React from "react";
|
|
@@ -3,8 +3,8 @@ import { ThemeProvider } from "styled-components";
|
|
|
3
3
|
import { theme } from "@adminjs/design-system";
|
|
4
4
|
import { parseHtml } from "../../utils/parseHtml.js";
|
|
5
5
|
import { StyledEditorShowWrapper, StyledShowLabel } from "./styles.js";
|
|
6
|
-
const EditorShow = ({ property, record }) => {
|
|
6
|
+
export const EditorShow = ({ property, record }) => {
|
|
7
7
|
const htmlContent = parseHtml(record.params[property.path]);
|
|
8
|
-
return (React.createElement(ThemeProvider, { theme: theme }, React.createElement(StyledEditorShowWrapper, null, React.createElement(StyledShowLabel, null, property.path), htmlContent && (React.createElement("div", { dangerouslySetInnerHTML: { __html: htmlContent } })))));
|
|
8
|
+
return (React.createElement(ThemeProvider, { theme: theme }, React.createElement(StyledEditorShowWrapper, null, React.createElement(StyledShowLabel, null, property.label ?? property.path), htmlContent && (React.createElement("div", { dangerouslySetInnerHTML: { __html: htmlContent } })))));
|
|
9
9
|
};
|
|
10
10
|
export default EditorShow;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
1
|
+
export { Editor } from "./Editor.js";
|
|
2
|
+
export { EditorShow } from "./EditorShow.js";
|
|
3
|
+
export { EditorList } from "./EditorList.js";
|
|
4
|
+
export { EditorFeature } from "./EditorFeature.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
1
|
+
export { Editor } from "./Editor.js";
|
|
2
|
+
export { EditorShow } from "./EditorShow.js";
|
|
3
|
+
export { EditorList } from "./EditorList.js";
|
|
4
|
+
export { EditorFeature } from "./EditorFeature.js";
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Box, Button, DrawerContent, DrawerFooter, Icon, Tab, Tabs } from "@adminjs/design-system";
|
|
2
|
+
import { styled } from "@adminjs/design-system/styled-components";
|
|
3
|
+
import React, { useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { BasePropertyComponent, LayoutElementRenderer, useRecord, useTranslation, ActionHeader, } from "adminjs";
|
|
5
|
+
const StyledTabButton = styled.button `
|
|
6
|
+
background: none;
|
|
7
|
+
border: none;
|
|
8
|
+
padding: ${({ theme }) => `${theme.space.sm} ${theme.space.xl}`};
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
border-bottom: 2px solid ${({ theme }) => theme.colors.border};
|
|
11
|
+
color: ${({ theme }) => theme.colors.grey60};
|
|
12
|
+
user-select: none;
|
|
13
|
+
${({ theme }) => ({
|
|
14
|
+
fontFamily: theme.font,
|
|
15
|
+
fontSize: theme.fontSizes.md,
|
|
16
|
+
lineHeight: theme.lineHeights.lg,
|
|
17
|
+
})};
|
|
18
|
+
${({ active, theme }) => active
|
|
19
|
+
? `
|
|
20
|
+
border-color: ${theme.colors.primary100};
|
|
21
|
+
color: ${theme.colors.primary100};
|
|
22
|
+
`
|
|
23
|
+
: ""}
|
|
24
|
+
`;
|
|
25
|
+
const StyledTabsContent = styled.div `
|
|
26
|
+
padding-top: ${({ theme }) => theme.space.xl};
|
|
27
|
+
`;
|
|
28
|
+
const TabButton = ({ onClick, active, tabId, role, children }) => (React.createElement(StyledTabButton, { type: "button", onClick: onClick, "data-tab-id": tabId, role: role, active: active }, children));
|
|
29
|
+
const DEFAULT_COMMON_LABEL = "Common";
|
|
30
|
+
const buildTabId = (label) => `tab-${label.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-_]/g, "")}`;
|
|
31
|
+
const groupProperties = (properties, commonLabel) => {
|
|
32
|
+
const commonProps = [];
|
|
33
|
+
const tabs = new Map();
|
|
34
|
+
properties.forEach((property) => {
|
|
35
|
+
const tab = property?.props?.tab ?? property?.custom?.tab;
|
|
36
|
+
if (tab) {
|
|
37
|
+
if (!tabs.has(tab)) {
|
|
38
|
+
tabs.set(tab, []);
|
|
39
|
+
}
|
|
40
|
+
tabs.get(tab)?.push(property);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
commonProps.push(property);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
const entries = [
|
|
47
|
+
{ id: "common", label: commonLabel, properties: commonProps },
|
|
48
|
+
];
|
|
49
|
+
tabs.forEach((props, label) => {
|
|
50
|
+
entries.push({
|
|
51
|
+
id: buildTabId(label),
|
|
52
|
+
label,
|
|
53
|
+
properties: props,
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
return entries;
|
|
57
|
+
};
|
|
58
|
+
export const FeatureTabsEdit = (props) => {
|
|
59
|
+
const { record: initialRecord, resource, action } = props;
|
|
60
|
+
const { record, handleChange, submit: handleSubmit, loading, setRecord, } = useRecord(initialRecord, resource.id);
|
|
61
|
+
const { translateButton } = useTranslation();
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (initialRecord) {
|
|
64
|
+
setRecord(initialRecord);
|
|
65
|
+
}
|
|
66
|
+
}, [initialRecord]);
|
|
67
|
+
const submit = (event) => {
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
handleSubmit().then((response) => {
|
|
70
|
+
if (response.data.redirectUrl) {
|
|
71
|
+
window.location.assign(response.data.redirectUrl);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return false;
|
|
75
|
+
};
|
|
76
|
+
const formTag = undefined;
|
|
77
|
+
const footerTag = undefined;
|
|
78
|
+
const commonLabel = resource?.options?.properties?.__featureTabsCommonLabel?.custom?.value ??
|
|
79
|
+
DEFAULT_COMMON_LABEL;
|
|
80
|
+
const tabs = useMemo(() => groupProperties(resource.editProperties, commonLabel), [resource.editProperties, commonLabel]);
|
|
81
|
+
const [currentTab, setCurrentTab] = useState(() => {
|
|
82
|
+
const commonHasProps = Boolean(tabs[0]?.properties?.length);
|
|
83
|
+
return commonHasProps ? "common" : tabs[1]?.id ?? "common";
|
|
84
|
+
});
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
const validTab = tabs.find((tab) => tab.id === currentTab);
|
|
87
|
+
if (!validTab) {
|
|
88
|
+
const commonHasProps = Boolean(tabs[0]?.properties?.length);
|
|
89
|
+
setCurrentTab(commonHasProps ? "common" : tabs[1]?.id ?? "common");
|
|
90
|
+
}
|
|
91
|
+
}, [tabs, currentTab]);
|
|
92
|
+
return (React.createElement(Box, { as: "form", onSubmit: submit, flex: true, flexDirection: "column" },
|
|
93
|
+
React.createElement(DrawerContent, null,
|
|
94
|
+
action?.showInDrawer ? React.createElement(ActionHeader, { ...props }) : null,
|
|
95
|
+
action.layout ? (action.layout.map((layoutElement, i) => (React.createElement(LayoutElementRenderer
|
|
96
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
97
|
+
, {
|
|
98
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
99
|
+
key: i, layoutElement: layoutElement, ...props, where: "edit", onChange: handleChange, record: record })))) : (React.createElement(Tabs, { currentTab: currentTab, onChange: setCurrentTab, buttonComponent: TabButton, contentComponent: StyledTabsContent }, tabs.map((tab) => (React.createElement(Tab, { key: tab.id, id: tab.id, label: tab.label }, tab.properties.map((property) => (React.createElement(BasePropertyComponent, { key: property.propertyPath, where: "edit", onChange: handleChange, property: property, resource: resource, record: record }))))))))),
|
|
100
|
+
React.createElement(DrawerFooter, null,
|
|
101
|
+
React.createElement(Button, { variant: "contained", type: "submit", "data-testid": "button-save", disabled: loading },
|
|
102
|
+
loading ? React.createElement(Icon, { icon: "Loader", spin: true }) : null,
|
|
103
|
+
translateButton("save", resource.id)))));
|
|
104
|
+
};
|
|
105
|
+
export default FeatureTabsEdit;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ComponentLoader, FeatureType } from "adminjs";
|
|
2
|
+
type FeatureTabsOptions = {
|
|
3
|
+
componentLoader?: ComponentLoader;
|
|
4
|
+
commonTabLabel?: string;
|
|
5
|
+
};
|
|
6
|
+
declare const FeatureTabsFeature: (config: FeatureTabsOptions) => FeatureType;
|
|
7
|
+
export declare const FeatureTabs: (config: FeatureTabsOptions) => FeatureType;
|
|
8
|
+
export default FeatureTabsFeature;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { buildFeature } from "adminjs";
|
|
2
|
+
import { bundleComponent } from "../../utils/bundle-component.js";
|
|
3
|
+
const COMPONENT_NAME = "FeatureTabs";
|
|
4
|
+
const FeatureTabsFeature = (config) => {
|
|
5
|
+
const { componentLoader, commonTabLabel } = config;
|
|
6
|
+
const editComponent = bundleComponent(componentLoader, COMPONENT_NAME, "FeatureTabsEdit.js");
|
|
7
|
+
const showComponent = bundleComponent(componentLoader, COMPONENT_NAME, "FeatureTabsShow.js");
|
|
8
|
+
return buildFeature({
|
|
9
|
+
actions: {
|
|
10
|
+
edit: {
|
|
11
|
+
component: editComponent,
|
|
12
|
+
},
|
|
13
|
+
show: {
|
|
14
|
+
component: showComponent,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
properties: {
|
|
18
|
+
__featureTabsCommonLabel: {
|
|
19
|
+
isVisible: false,
|
|
20
|
+
custom: {
|
|
21
|
+
value: commonTabLabel,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
export const FeatureTabs = FeatureTabsFeature;
|
|
28
|
+
export default FeatureTabsFeature;
|