commit
5deaa35ef3
|
@ -1,11 +0,0 @@
|
|||
import { request } from "@strapi/helper-plugin";
|
||||
|
||||
const explorerRequests = {
|
||||
getContentTypes: async () => {
|
||||
return await request("/content-type-explorer/get-content-types", {
|
||||
method: "GET",
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default explorerRequests;
|
|
@ -5,14 +5,20 @@
|
|||
*/
|
||||
|
||||
import React from "react";
|
||||
import { Badge, Box, Divider, Tooltip, Typography } from "@strapi/design-system";
|
||||
import {
|
||||
Badge,
|
||||
Box,
|
||||
Divider,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@strapi/design-system";
|
||||
import { useTheme } from "styled-components";
|
||||
import { Handle } from "reactflow";
|
||||
import { RelationIcon } from "./RelationIcon";
|
||||
import { getIcon } from "../utils/themeUtils";
|
||||
import "./CustomNode.css";
|
||||
|
||||
export default function CustomNode({ data }) {
|
||||
export function CustomNode({ data }) {
|
||||
let attributesToShow = Object.entries(data.attributes);
|
||||
|
||||
if (data.options.showRelationsOnly) {
|
||||
|
@ -34,13 +40,28 @@ export default function CustomNode({ data }) {
|
|||
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Box background="neutral0" shadow="tableShadow" hasRadius padding="16px 24px" className="cte-plugin-box">
|
||||
<Typography fontWeight="bold" textColor="buttonPrimary500" padding="16px" className="cte-plugin-header nodrag">
|
||||
<Box
|
||||
background="neutral0"
|
||||
shadow="tableShadow"
|
||||
hasRadius
|
||||
padding="16px 24px"
|
||||
className="cte-plugin-box"
|
||||
>
|
||||
<Typography
|
||||
fontWeight="bold"
|
||||
textColor="buttonPrimary500"
|
||||
padding="16px"
|
||||
className="cte-plugin-header nodrag"
|
||||
>
|
||||
{data.info.displayName}
|
||||
</Typography>
|
||||
|
||||
<br />
|
||||
<Typography textColor="neutral400" padding="16px" className="cte-plugin-header nodrag">
|
||||
<Typography
|
||||
textColor="neutral400"
|
||||
padding="16px"
|
||||
className="cte-plugin-header nodrag"
|
||||
>
|
||||
{data.key}
|
||||
<Handle
|
||||
type="target"
|
||||
|
@ -61,7 +82,11 @@ export default function CustomNode({ data }) {
|
|||
<p className="cte-plugin-line nodrag">{attr[0]}</p>
|
||||
|
||||
{data.options.showTypes && (
|
||||
<Badge size="M" backgroundColor="neutral0" textColor="neutral400">
|
||||
<Badge
|
||||
size="M"
|
||||
backgroundColor="neutral0"
|
||||
textColor="neutral400"
|
||||
>
|
||||
{attr[1].type}
|
||||
</Badge>
|
||||
)}
|
||||
|
@ -70,9 +95,16 @@ export default function CustomNode({ data }) {
|
|||
{attr[1].type === "relation" && (
|
||||
<>
|
||||
<Tooltip description={attr[1].relation}>
|
||||
<RelationIcon theme={theme}>{getIcon(attr[1].relation)}</RelationIcon>
|
||||
<RelationIcon theme={theme}>
|
||||
{getIcon(attr[1].relation)}
|
||||
</RelationIcon>
|
||||
</Tooltip>
|
||||
<Handle type="source" id={attr[0]} position="right" className="cte-plugin-handle" />
|
||||
<Handle
|
||||
type="source"
|
||||
id={attr[0]}
|
||||
position="right"
|
||||
className="cte-plugin-handle"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
import {
|
||||
ModalLayout,
|
||||
ModalHeader,
|
||||
ModalFooter,
|
||||
ModalBody,
|
||||
Button,
|
||||
Typography,
|
||||
SingleSelect,
|
||||
SingleSelectOption,
|
||||
NumberInput,
|
||||
} from "@strapi/design-system";
|
||||
import { toJpeg, toPng, toSvg } from "html-to-image";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useDigramStore } from "../store";
|
||||
import { useTheme } from "styled-components";
|
||||
|
||||
export function ExportModal({ imageRef }) {
|
||||
const theme = useTheme();
|
||||
|
||||
const { setShowModal } = useDigramStore();
|
||||
|
||||
const [format, setFormat] = useState("png");
|
||||
const [quality, setQuality] = useState(0.95);
|
||||
|
||||
function downloadImage(dataUrl, fileExtension) {
|
||||
const link = document.createElement("a");
|
||||
link.download = `strapi-diagram-${new Date()
|
||||
.toISOString()
|
||||
.replace(/[-:T.]/g, "")
|
||||
.slice(0, -5)}.${fileExtension}`;
|
||||
link.href = dataUrl;
|
||||
link.click();
|
||||
}
|
||||
|
||||
const exportDiagram = useCallback(() => {
|
||||
if (imageRef.current === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const filter = (node) => {
|
||||
const exclusionClasses = ["cte-plugin-controls"];
|
||||
return !exclusionClasses.some((classname) =>
|
||||
node.classList?.contains(classname)
|
||||
);
|
||||
};
|
||||
|
||||
if (format == "png") {
|
||||
toPng(imageRef.current, {
|
||||
cacheBust: true,
|
||||
filter: filter,
|
||||
style: {
|
||||
background: theme.colors.neutral100,
|
||||
},
|
||||
})
|
||||
.then((dataUrl) => {
|
||||
downloadImage(dataUrl, "png");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
} else if (format == "svg") {
|
||||
toSvg(imageRef.current, {
|
||||
cacheBust: true,
|
||||
filter: filter,
|
||||
style: {
|
||||
background: theme.colors.neutral100,
|
||||
},
|
||||
})
|
||||
.then((dataUrl) => {
|
||||
downloadImage(dataUrl, "svg");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
} else if (format == "jpeg") {
|
||||
toJpeg(imageRef.current, {
|
||||
cacheBust: true,
|
||||
filter: filter,
|
||||
quality: quality,
|
||||
style: {
|
||||
background: theme.colors.neutral100,
|
||||
},
|
||||
})
|
||||
.then((dataUrl) => {
|
||||
downloadImage(dataUrl, "jpeg");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
}, [imageRef, quality, format]);
|
||||
|
||||
return (
|
||||
<ModalLayout onClose={() => setShowModal(false)}>
|
||||
<ModalHeader>
|
||||
<Typography fontWeight="bold" textColor="neutral800" as="h2" id="title">
|
||||
Export Diagram
|
||||
</Typography>
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<SingleSelect
|
||||
label="Format"
|
||||
onClear={() => {
|
||||
setFormat(undefined);
|
||||
}}
|
||||
value={format}
|
||||
onChange={setFormat}
|
||||
>
|
||||
<SingleSelectOption value="svg">SVG</SingleSelectOption>
|
||||
<SingleSelectOption value="png">PNG</SingleSelectOption>
|
||||
<SingleSelectOption value="jpeg">JPEG</SingleSelectOption>
|
||||
</SingleSelect>
|
||||
<span style={{ height: "16px", display: "block" }} />
|
||||
{format == "jpeg" && (
|
||||
<NumberInput
|
||||
label="Quality"
|
||||
name="quality"
|
||||
hint="0.0 - 1.0"
|
||||
onValueChange={(value) => setQuality(value)}
|
||||
value={quality}
|
||||
/>
|
||||
)}
|
||||
</ModalBody>
|
||||
<ModalFooter
|
||||
endActions={<Button onClick={exportDiagram}>Export</Button>}
|
||||
/>
|
||||
</ModalLayout>
|
||||
);
|
||||
}
|
|
@ -4,14 +4,16 @@ import {
|
|||
SingleSelectOption,
|
||||
} from "@strapi/design-system";
|
||||
import React from "react";
|
||||
import { useDigramStore } from "../store";
|
||||
|
||||
export default function OptionsBar({ options, toggleOption }) {
|
||||
export function OptionsBar() {
|
||||
const { options, toggleOption } = useDigramStore();
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "center",
|
||||
alignItems: "flex-start",
|
||||
padding: "0 56px 24px",
|
||||
gap: "24px",
|
||||
}}
|
||||
|
@ -23,14 +25,14 @@ export default function OptionsBar({ options, toggleOption }) {
|
|||
}}
|
||||
value={options.showTypes}
|
||||
>
|
||||
Fields Data Types
|
||||
Data Types
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
name="show-icons"
|
||||
onValueChange={() => toggleOption("showIcons")}
|
||||
value={options.showIcons}
|
||||
>
|
||||
Fields Icons
|
||||
Data Type Icons
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
name="show-default-fields"
|
||||
|
|
|
@ -1,48 +1,49 @@
|
|||
/*
|
||||
*
|
||||
* HomePage
|
||||
*
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { HeaderLayout, Icon, LinkButton } from "@strapi/design-system";
|
||||
import explorerRequests from "../../api/explorer-api";
|
||||
import { Question, Search, Drag } from "@strapi/icons";
|
||||
import { useTheme } from "styled-components";
|
||||
import { SmartBezierEdge, SmartStepEdge, SmartStraightEdge } from "@tisoap/react-flow-smart-edge";
|
||||
import CustomNode from "../../components/CustomNode";
|
||||
import { createEdegs, createNodes, updateEdges, updateNodes } from "../../utils/dataUtils";
|
||||
import { Background, ControlButton, Controls, ReactFlow, useEdgesState, useNodesState } from "reactflow";
|
||||
import { getBackgroundColor } from "../../utils/themeUtils";
|
||||
import "reactflow/dist/style.css";
|
||||
import OptionsBar from "../../components/OptionsBar";
|
||||
import "./styles.css";
|
||||
import React, { useEffect, useMemo, useRef } from "react";
|
||||
import { useFetchClient } from "@strapi/helper-plugin";
|
||||
import { HeaderLayout, Icon, Button } from "@strapi/design-system";
|
||||
import { Search, Drag, Download, Refresh } from "@strapi/icons";
|
||||
import { useTheme } from "styled-components";
|
||||
import {
|
||||
SmartBezierEdge,
|
||||
SmartStepEdge,
|
||||
SmartStraightEdge,
|
||||
} from "@tisoap/react-flow-smart-edge";
|
||||
import { Background, ControlButton, Controls, ReactFlow } from "reactflow";
|
||||
import { getBackgroundColor } from "../../utils/themeUtils";
|
||||
import { useDigramStore } from "../../store";
|
||||
import { CustomNode } from "../../components/CustomNode";
|
||||
import { OptionsBar } from "../../components/OptionsBar";
|
||||
import { ExportModal } from "../../components/ExportModal";
|
||||
|
||||
const useEffectSkipInitial = (func, deps) => {
|
||||
const didMount = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (didMount.current) func();
|
||||
else didMount.current = true;
|
||||
}, deps);
|
||||
};
|
||||
|
||||
const HomePage = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
const [contentTypes, setContentTypes] = useState([]);
|
||||
|
||||
const [options, setOptions] = useState({
|
||||
snapToGrid: false,
|
||||
showTypes: true,
|
||||
showIcons: true,
|
||||
showRelationsOnly: false,
|
||||
showAdminTypes: false,
|
||||
showDefaultFields: false,
|
||||
showPluginTypes: false,
|
||||
showEdges: false,
|
||||
scrollMode: true,
|
||||
edgeType: "smartbezier",
|
||||
backgroundPattern: "dots",
|
||||
});
|
||||
|
||||
function toggleOption(optionName, optionValue = null) {
|
||||
setOptions({
|
||||
...options,
|
||||
[optionName]: optionValue || !options[optionName],
|
||||
});
|
||||
}
|
||||
const { get } = useFetchClient();
|
||||
const {
|
||||
nodes,
|
||||
redrawEdges,
|
||||
edges,
|
||||
onNodesChange,
|
||||
onEdgesChange,
|
||||
onConnect,
|
||||
redrawNodes,
|
||||
drawDiagram,
|
||||
toggleOption,
|
||||
options,
|
||||
setData,
|
||||
showModal,
|
||||
setShowModal,
|
||||
} = useDigramStore();
|
||||
|
||||
const nodeTypes = useMemo(() => ({ special: CustomNode }), []);
|
||||
const edgeTypes = useMemo(
|
||||
|
@ -54,66 +55,59 @@ const HomePage = () => {
|
|||
[]
|
||||
);
|
||||
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||
const regenrate = async () => {
|
||||
const { data } = await get(`/strapi-content-type-explorer/get-types`);
|
||||
setData(data);
|
||||
drawDiagram();
|
||||
};
|
||||
|
||||
const onConnect = useCallback((params) => setEdges((eds) => addEdge(params, eds)), [setEdges]);
|
||||
|
||||
// get (and filter) content-types
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
let allTypes = await explorerRequests.getContentTypes();
|
||||
if (!options.showAdminTypes) {
|
||||
allTypes = allTypes.filter((x) => !x.name.startsWith("admin::"));
|
||||
}
|
||||
if (!options.showPluginTypes) {
|
||||
allTypes = allTypes.filter((x) => !x.name.startsWith("plugin::"));
|
||||
}
|
||||
setContentTypes(allTypes);
|
||||
};
|
||||
|
||||
fetchData();
|
||||
useEffectSkipInitial(() => {
|
||||
regenrate();
|
||||
}, [options.showAdminTypes, options.showPluginTypes]);
|
||||
|
||||
// create nodes & edges
|
||||
useEffect(() => {
|
||||
if (contentTypes.length > 0) {
|
||||
let newNodes = createNodes(contentTypes, options);
|
||||
setNodes(newNodes);
|
||||
let newEdges = createEdegs(contentTypes, options);
|
||||
setEdges(newEdges);
|
||||
}
|
||||
}, [contentTypes]);
|
||||
redrawEdges();
|
||||
}, [options.edgeType, options.showEdges]);
|
||||
|
||||
useEffect(() => {
|
||||
let newEdges = updateEdges(edges, options);
|
||||
setEdges(newEdges);
|
||||
}, [setEdges, options.edgeType, options.showEdges]);
|
||||
redrawNodes();
|
||||
}, [
|
||||
options.showTypes,
|
||||
options.showIcons,
|
||||
options.showRelationsOnly,
|
||||
options.showDefaultFields,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
let newNodes = updateNodes(nodes, options);
|
||||
setNodes(newNodes);
|
||||
}, [setNodes, options.showTypes, options.showIcons, options.showRelationsOnly, options.showDefaultFields]);
|
||||
const ref = useRef(null);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: "flex", flexDirection: "column", height: "100vh" }}>
|
||||
<HeaderLayout
|
||||
title="Content-Type Explorer"
|
||||
// primaryAction={<Button>Download as Image</Button>}
|
||||
secondaryAction={
|
||||
<LinkButton
|
||||
variant="secondary"
|
||||
startIcon={<Question />}
|
||||
href="https://github.com/shahriarkh/strapi-content-type-explorer"
|
||||
primaryAction={
|
||||
<Button
|
||||
variant="primary"
|
||||
startIcon={<Download />}
|
||||
onClick={() => setShowModal(true)}
|
||||
>
|
||||
Help
|
||||
</LinkButton>
|
||||
Export Diagram
|
||||
</Button>
|
||||
}
|
||||
secondaryAction={
|
||||
<Button
|
||||
variant="secondary"
|
||||
startIcon={<Refresh />}
|
||||
onClick={regenrate}
|
||||
>
|
||||
Regenrate
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<OptionsBar options={options} toggleOption={toggleOption} />
|
||||
<OptionsBar />
|
||||
<div
|
||||
ref={ref}
|
||||
style={{
|
||||
height: "100vh",
|
||||
height: "100%",
|
||||
borderTop: `1px solid ${theme.colors.neutral150}`,
|
||||
}}
|
||||
>
|
||||
|
@ -144,8 +138,14 @@ const HomePage = () => {
|
|||
"--button-hover": theme.colors.buttonPrimary500,
|
||||
}}
|
||||
>
|
||||
<ControlButton onClick={() => toggleOption("scrollMode")} title="Toggle Mouse Wheel Behavior (Zoom/Scroll)">
|
||||
<Icon color="neutral1000" as={options.scrollMode ? Drag : Search} />
|
||||
<ControlButton
|
||||
onClick={() => toggleOption("scrollMode")}
|
||||
title="Toggle Mouse Wheel Behavior (Zoom/Scroll)"
|
||||
>
|
||||
<Icon
|
||||
color="neutral1000"
|
||||
as={options.scrollMode ? Drag : Search}
|
||||
/>
|
||||
</ControlButton>
|
||||
</Controls>
|
||||
<Background
|
||||
|
@ -153,8 +153,9 @@ const HomePage = () => {
|
|||
color={getBackgroundColor(options.backgroundPattern, theme)}
|
||||
/>
|
||||
</ReactFlow>
|
||||
{showModal && <ExportModal imageRef={ref} />}
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
import { addEdge, applyNodeChanges, applyEdgeChanges } from "reactflow";
|
||||
import {
|
||||
createEdegs,
|
||||
createNodes,
|
||||
updateEdges,
|
||||
updateNodes,
|
||||
} from "../utils/dataUtils";
|
||||
|
||||
export const useDigramStore = create(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
nodes: [],
|
||||
edges: [],
|
||||
data: [],
|
||||
showModal: false,
|
||||
options: {
|
||||
snapToGrid: false,
|
||||
showTypes: true,
|
||||
showIcons: true,
|
||||
showRelationsOnly: false,
|
||||
showAdminTypes: false,
|
||||
showDefaultFields: false,
|
||||
showPluginTypes: false,
|
||||
showEdges: false,
|
||||
scrollMode: true,
|
||||
edgeType: "smartbezier",
|
||||
backgroundPattern: "dots",
|
||||
},
|
||||
setData: (contentTypesData) => {
|
||||
set({
|
||||
data: contentTypesData,
|
||||
});
|
||||
},
|
||||
setShowModal: (bool) => {
|
||||
set({
|
||||
showModal: bool,
|
||||
});
|
||||
},
|
||||
toggleOption: (optionName, optionValue = null) => {
|
||||
let newOptions = {
|
||||
...get().options,
|
||||
[optionName]: optionValue || !get().options[optionName],
|
||||
};
|
||||
set({
|
||||
options: newOptions,
|
||||
});
|
||||
},
|
||||
onNodesChange: (changes) => {
|
||||
set({
|
||||
nodes: applyNodeChanges(changes, get().nodes),
|
||||
});
|
||||
},
|
||||
onEdgesChange: (changes) => {
|
||||
set({
|
||||
edges: applyEdgeChanges(changes, get().edges),
|
||||
});
|
||||
},
|
||||
onConnect: (connection) => {
|
||||
set({
|
||||
edges: addEdge(connection, get().edges),
|
||||
});
|
||||
},
|
||||
drawDiagram: () => {
|
||||
const options = get().options;
|
||||
let typesToDraw = get().data;
|
||||
if (!options.showAdminTypes) {
|
||||
typesToDraw = typesToDraw.filter(
|
||||
(x) => !x.name.startsWith("admin::")
|
||||
);
|
||||
}
|
||||
if (!options.showPluginTypes) {
|
||||
typesToDraw = typesToDraw.filter(
|
||||
(x) => !x.name.startsWith("plugin::")
|
||||
);
|
||||
}
|
||||
let newNodes = createNodes(typesToDraw, options);
|
||||
let newEdges = createEdegs(typesToDraw, options);
|
||||
set({
|
||||
nodes: newNodes,
|
||||
edges: newEdges,
|
||||
});
|
||||
},
|
||||
redrawNodes: () => {
|
||||
let newNodes = updateNodes(get().nodes, get().options);
|
||||
set({
|
||||
nodes: newNodes,
|
||||
});
|
||||
},
|
||||
redrawEdges: () => {
|
||||
let newEdges = updateEdges(get().edges, get().options);
|
||||
set({
|
||||
edges: newEdges,
|
||||
});
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: "strapi-content-type-explorer",
|
||||
}
|
||||
)
|
||||
);
|
|
@ -10,7 +10,9 @@ export function createNodes(contentTypes, options) {
|
|||
id: node.key,
|
||||
position: {
|
||||
x: (index % CARDS_PER_ROW) * 320,
|
||||
y: ((index - (index % CARDS_PER_ROW)) / CARDS_PER_ROW) * 560,
|
||||
y:
|
||||
((index - (index % CARDS_PER_ROW)) / CARDS_PER_ROW) * 560 +
|
||||
(index % 2) * 48,
|
||||
},
|
||||
type: "special",
|
||||
|
||||
|
@ -38,7 +40,11 @@ export function createEdegs(contentTypes, options) {
|
|||
Object.keys(contentType.attributes).map((attr) => {
|
||||
if (contentType.attributes[attr].type == "relation") {
|
||||
// only add edge if target node is not excluded (not hidden)
|
||||
if (contentTypes.some((node) => node.key === contentType.attributes[attr].target)) {
|
||||
if (
|
||||
contentTypes.some(
|
||||
(node) => node.key === contentType.attributes[attr].target
|
||||
)
|
||||
) {
|
||||
newEdges = [
|
||||
...newEdges,
|
||||
{
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
Media,
|
||||
Boolean,
|
||||
Json,
|
||||
Blocks,
|
||||
Relation,
|
||||
Uid,
|
||||
OneToMany,
|
||||
|
@ -67,6 +68,8 @@ export function getIcon(attrType) {
|
|||
return <RichText />;
|
||||
case "media":
|
||||
return <Media />;
|
||||
case "blocks":
|
||||
return <Blocks />;
|
||||
|
||||
case "onetomany": //
|
||||
return <OneToMany />;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
|
@ -13,12 +13,10 @@
|
|||
"url": "https://github.com/shahriarkh/strapi-content-type-explorer.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@strapi/design-system": "^1.6.3",
|
||||
"@strapi/helper-plugin": "^4.6.0",
|
||||
"@strapi/icons": "^1.6.3",
|
||||
"prop-types": "^15.7.2",
|
||||
"reactflow": "^11.7.4",
|
||||
"@tisoap/react-flow-smart-edge": "^3.0.0"
|
||||
"@tisoap/react-flow-smart-edge": "^3.0.0",
|
||||
"html-to-image": "^1.11.11",
|
||||
"reactflow": "^11.10.2",
|
||||
"zustand": "^4.4.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@strapi/strapi": "^4.0.0"
|
||||
|
|
|
@ -1,20 +1,11 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = ({ strapi }) => ({
|
||||
getContentTypes(ctx) {
|
||||
const data = strapi
|
||||
.plugin("content-type-explorer")
|
||||
.service("explorerService")
|
||||
async getTypes(ctx) {
|
||||
const contentTypes = await strapi
|
||||
.service("plugin::strapi-content-type-explorer.explorerService")
|
||||
.getContentTypes();
|
||||
|
||||
let neededData = Object.keys(data).map((key) => ({
|
||||
name: key,
|
||||
attributes: data[key]["attributes"],
|
||||
info: data[key]["info"],
|
||||
// kind: data[key]["kind"],
|
||||
key: data[key]["uid"],
|
||||
}));
|
||||
|
||||
ctx.body = neededData;
|
||||
ctx.body = contentTypes;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
'use strict';
|
||||
"use strict";
|
||||
|
||||
const register = require('./register');
|
||||
const bootstrap = require('./bootstrap');
|
||||
const destroy = require('./destroy');
|
||||
const config = require('./config');
|
||||
const contentTypes = require('./content-types');
|
||||
const controllers = require('./controllers');
|
||||
const routes = require('./routes');
|
||||
const middlewares = require('./middlewares');
|
||||
const policies = require('./policies');
|
||||
const services = require('./services');
|
||||
const register = require("./register");
|
||||
const bootstrap = require("./bootstrap");
|
||||
const destroy = require("./destroy");
|
||||
const config = require("./config");
|
||||
const contentTypes = require("./content-types");
|
||||
const controllers = require("./controllers");
|
||||
const routes = require("./routes");
|
||||
const middlewares = require("./middlewares");
|
||||
const policies = require("./policies");
|
||||
const services = require("./services");
|
||||
|
||||
module.exports = {
|
||||
register,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
module.exports = [
|
||||
{
|
||||
method: "GET",
|
||||
path: "/get-content-types",
|
||||
handler: "explorerController.getContentTypes",
|
||||
path: "/get-types",
|
||||
handler: "explorerController.getTypes",
|
||||
config: {
|
||||
policies: [],
|
||||
auth: false,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = ({ strapi }) => ({
|
||||
getContentTypes() {
|
||||
return strapi.contentTypes;
|
||||
async getContentTypes() {
|
||||
const types = strapi.contentTypes;
|
||||
|
||||
let formattedTypes = Object.keys(types).map((key) => ({
|
||||
name: key,
|
||||
attributes: types[key]["attributes"],
|
||||
info: types[key]["info"],
|
||||
// kind: data[key]["kind"],
|
||||
key: types[key]["uid"],
|
||||
}));
|
||||
|
||||
return formattedTypes;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
'use strict';
|
||||
"use strict";
|
||||
|
||||
module.exports = require('./admin/src').default;
|
||||
module.exports = require("./admin/src").default;
|
||||
|
|
Loading…
Reference in New Issue