Add files via upload
parent
672757694c
commit
e19bd0a7ca
|
@ -0,0 +1,3 @@
|
|||
# Strapi plugin content-type-explorer
|
||||
|
||||
A quick description of content-type-explorer.
|
|
@ -0,0 +1,11 @@
|
|||
import { request } from "@strapi/helper-plugin";
|
||||
|
||||
const explorerRequests = {
|
||||
getContentTypes: async () => {
|
||||
return await request("/content-type-explorer/get-content-types", {
|
||||
method: "GET",
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default explorerRequests;
|
|
@ -0,0 +1,35 @@
|
|||
.cte-plugin-box {
|
||||
position: relative;
|
||||
min-width: 280px;
|
||||
}
|
||||
|
||||
.cte-plugin-header {
|
||||
user-select: text;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.cte-plugin-line {
|
||||
margin-right: auto;
|
||||
padding-right: 12px; /*minimum gap*/
|
||||
margin-top: -2px;
|
||||
user-select: text;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.cte-plugin-handle {
|
||||
position: absolute;
|
||||
right: -27px;
|
||||
top: 6px;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.cte-plugin-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/**
|
||||
*
|
||||
* PluginIcon
|
||||
*
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import {
|
||||
Badge,
|
||||
Box,
|
||||
Divider,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from "@strapi/design-system";
|
||||
import { useTheme } from "styled-components";
|
||||
import { Handle } from "reactflow";
|
||||
import { RelationIndicator } from "./RelationIndicator";
|
||||
import { getIcon } from "../utils/themeUtils";
|
||||
import "./CustomNode.css";
|
||||
|
||||
export default function CustomNode({ data }) {
|
||||
let attributesToShow = Object.entries(data.attributes);
|
||||
|
||||
if (data.options.showRelationsOnly) {
|
||||
attributesToShow = attributesToShow.filter((x) => x[1].type === "relation");
|
||||
}
|
||||
|
||||
if (!data.options.showDefaultFields) {
|
||||
attributesToShow = attributesToShow.filter(
|
||||
(x) =>
|
||||
!(
|
||||
x[0] === "updatedAt" ||
|
||||
x[0] === "createdAt" ||
|
||||
x[0] === "updatedBy" ||
|
||||
x[0] === "createdBy" ||
|
||||
x[0] === "publishedAt"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
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"
|
||||
>
|
||||
{data.info.displayName}
|
||||
</Typography>
|
||||
|
||||
<br />
|
||||
<Typography
|
||||
textColor="neutral400"
|
||||
padding="16px"
|
||||
className="cte-plugin-header nodrag"
|
||||
>
|
||||
{data.key}
|
||||
<Handle
|
||||
type="target"
|
||||
position="top"
|
||||
style={{
|
||||
borderColor: theme.colors.neutral200,
|
||||
background: theme.colors.neutral0,
|
||||
}}
|
||||
/>
|
||||
</Typography>
|
||||
|
||||
<Divider style={{ margin: "8px 0" }} />
|
||||
|
||||
{attributesToShow.map((attr) => {
|
||||
return (
|
||||
<Typography key={attr[0]}>
|
||||
<div className="cte-plugin-field">
|
||||
<p className="cte-plugin-line nodrag">{attr[0]}</p>
|
||||
|
||||
{data.options.showTypes && (
|
||||
<Badge
|
||||
size="M"
|
||||
backgroundColor="neutral0"
|
||||
textColor="neutral400"
|
||||
>
|
||||
{attr[1].type}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
{data.options.showIcons && getIcon(attr[1].type)}
|
||||
{attr[1].type === "relation" && (
|
||||
<>
|
||||
<Tooltip description={attr[1].relation}>
|
||||
<RelationIndicator theme={theme}>
|
||||
{getIcon(attr[1].relation)}
|
||||
</RelationIndicator>
|
||||
</Tooltip>
|
||||
<Handle
|
||||
type="source"
|
||||
id={attr[0]}
|
||||
position="right"
|
||||
className="cte-plugin-handle"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Typography>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
*
|
||||
* Initializer
|
||||
*
|
||||
*/
|
||||
|
||||
import { useEffect, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import pluginId from '../../pluginId';
|
||||
|
||||
const Initializer = ({ setPlugin }) => {
|
||||
const ref = useRef();
|
||||
ref.current = setPlugin;
|
||||
|
||||
useEffect(() => {
|
||||
ref.current(pluginId);
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
Initializer.propTypes = {
|
||||
setPlugin: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default Initializer;
|
|
@ -0,0 +1,110 @@
|
|||
import {
|
||||
Checkbox,
|
||||
SingleSelect,
|
||||
SingleSelectOption,
|
||||
} from "@strapi/design-system";
|
||||
import React from "react";
|
||||
|
||||
export default function OptionsBar({ options, toggleOption }) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "center",
|
||||
padding: "0 56px 24px",
|
||||
gap: "24px",
|
||||
}}
|
||||
>
|
||||
<Checkbox
|
||||
name="show-type-names"
|
||||
onValueChange={() => {
|
||||
toggleOption("showTypes");
|
||||
}}
|
||||
value={options.showTypes}
|
||||
>
|
||||
Fields Data Types
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
name="show-icons"
|
||||
onValueChange={() => toggleOption("showIcons")}
|
||||
value={options.showIcons}
|
||||
>
|
||||
Fields Icons
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
name="show-default-fields"
|
||||
onValueChange={() => toggleOption("showDefaultFields")}
|
||||
value={options.showDefaultFields}
|
||||
>
|
||||
Default Fields
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
name="show-relations-only"
|
||||
onValueChange={() => toggleOption("showRelationsOnly")}
|
||||
value={options.showRelationsOnly}
|
||||
>
|
||||
Relational Fields Only
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
name="show-admin-types"
|
||||
onValueChange={() => toggleOption("showAdminTypes")}
|
||||
value={options.showAdminTypes}
|
||||
>
|
||||
admin:: Types
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
name="show-plugin-types"
|
||||
onValueChange={() => toggleOption("showPluginTypes")}
|
||||
value={options.showPluginTypes}
|
||||
>
|
||||
plugin:: Types
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
name="show-edges"
|
||||
onValueChange={() => toggleOption("showEdges")}
|
||||
value={options.showEdges}
|
||||
>
|
||||
Edges
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
name="snap-to-grid"
|
||||
onValueChange={() => toggleOption("snapToGrid")}
|
||||
value={options.snapToGrid}
|
||||
>
|
||||
Snap To Grid
|
||||
</Checkbox>
|
||||
<div style={{ flexGrow: 1 }} />
|
||||
<SingleSelect
|
||||
// label="Edge Type"
|
||||
value={options.edgeType}
|
||||
onChange={(type) => toggleOption("edgeType", type)}
|
||||
>
|
||||
<SingleSelectOption value="smartbezier">
|
||||
Smart Bezier
|
||||
</SingleSelectOption>
|
||||
<SingleSelectOption value="smartstraight">
|
||||
Smart Straight
|
||||
</SingleSelectOption>
|
||||
<SingleSelectOption value="smartstep">Smart Step</SingleSelectOption>
|
||||
<SingleSelectOption value="default">Bezier</SingleSelectOption>
|
||||
<SingleSelectOption value="simplebezier">
|
||||
Simple Bezier
|
||||
</SingleSelectOption>
|
||||
<SingleSelectOption value="straight">Straight</SingleSelectOption>
|
||||
<SingleSelectOption value="step">Step</SingleSelectOption>
|
||||
<SingleSelectOption value="smoothstep">Smooth Step</SingleSelectOption>
|
||||
</SingleSelect>
|
||||
<SingleSelect
|
||||
// label="Background"
|
||||
value={options.backgroundPattern}
|
||||
onChange={(pattern) => toggleOption("backgroundPattern", pattern)}
|
||||
>
|
||||
<SingleSelectOption value="dots">Dots</SingleSelectOption>
|
||||
<SingleSelectOption value="lines">Lines</SingleSelectOption>
|
||||
<SingleSelectOption value="cross">Cross</SingleSelectOption>
|
||||
<SingleSelectOption value="none">None</SingleSelectOption>
|
||||
</SingleSelect>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
*
|
||||
* PluginIcon
|
||||
*
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { OneToMany } from "@strapi/icons";
|
||||
|
||||
const PluginIcon = () => <OneToMany />;
|
||||
|
||||
export default PluginIcon;
|
|
@ -0,0 +1,21 @@
|
|||
import styled from "styled-components";
|
||||
|
||||
export const RelationIndicator = styled.span`
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: ${(props) => props.theme.colors.neutral0};
|
||||
position: absolute;
|
||||
right: -32px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
|
||||
svg path {
|
||||
fill: ${(props) => props.theme.colors.buttonPrimary500};
|
||||
}
|
||||
`;
|
|
@ -0,0 +1,65 @@
|
|||
import { prefixPluginTranslations } from "@strapi/helper-plugin";
|
||||
import pluginPkg from "../../package.json";
|
||||
import pluginId from "./pluginId";
|
||||
import Initializer from "./components/Initializer";
|
||||
import PluginIcon from "./components/PluginIcon";
|
||||
|
||||
const name = pluginPkg.strapi.name;
|
||||
|
||||
export default {
|
||||
register(app) {
|
||||
app.addMenuLink({
|
||||
to: `/plugins/${pluginId}`,
|
||||
icon: PluginIcon,
|
||||
intlLabel: {
|
||||
id: `${pluginId}.plugin.name`,
|
||||
defaultMessage: "Content-Type Explorer",
|
||||
},
|
||||
Component: async () => {
|
||||
const component = await import(
|
||||
/* webpackChunkName: "[request]" */ "./pages/App"
|
||||
);
|
||||
|
||||
return component;
|
||||
},
|
||||
permissions: [
|
||||
// Uncomment to set the permissions of the plugin here
|
||||
// {
|
||||
// action: '', // the action name should be plugin::plugin-name.actionType
|
||||
// subject: null,
|
||||
// },
|
||||
],
|
||||
});
|
||||
app.registerPlugin({
|
||||
id: pluginId,
|
||||
initializer: Initializer,
|
||||
isReady: false,
|
||||
name,
|
||||
});
|
||||
},
|
||||
|
||||
bootstrap(app) {},
|
||||
async registerTrads({ locales }) {
|
||||
const importedTrads = await Promise.all(
|
||||
locales.map((locale) => {
|
||||
return import(
|
||||
/* webpackChunkName: "translation-[request]" */ `./translations/${locale}.json`
|
||||
)
|
||||
.then(({ default: data }) => {
|
||||
return {
|
||||
data: prefixPluginTranslations(data, pluginId),
|
||||
locale,
|
||||
};
|
||||
})
|
||||
.catch(() => {
|
||||
return {
|
||||
data: {},
|
||||
locale,
|
||||
};
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
return Promise.resolve(importedTrads);
|
||||
},
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
*
|
||||
* This component is the skeleton around the actual pages, and should only
|
||||
* contain code that should be seen on all pages. (e.g. navigation bar)
|
||||
*
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Switch, Route } from 'react-router-dom';
|
||||
import { AnErrorOccurred } from '@strapi/helper-plugin';
|
||||
import pluginId from '../../pluginId';
|
||||
import HomePage from '../HomePage';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<div>
|
||||
<Switch>
|
||||
<Route path={`/plugins/${pluginId}`} component={HomePage} exact />
|
||||
<Route component={AnErrorOccurred} />
|
||||
</Switch>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
*
|
||||
* HomePage
|
||||
*
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { Button, 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 } 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";
|
||||
|
||||
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 nodeTypes = useMemo(() => ({ special: CustomNode }), []);
|
||||
const edgeTypes = useMemo(
|
||||
() => ({
|
||||
smartbezier: SmartBezierEdge,
|
||||
smartstep: SmartStepEdge,
|
||||
smartstraight: SmartStraightEdge,
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
||||
|
||||
const onConnect = useCallback(
|
||||
(params) => setEdges((eds) => addEdge(params, eds)),
|
||||
[setEdges]
|
||||
);
|
||||
|
||||
// Show/hide content types on options change
|
||||
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();
|
||||
}, [options.showAdminTypes, options.showPluginTypes]);
|
||||
|
||||
// Create/update nodes & edges
|
||||
useEffect(() => {
|
||||
if (contentTypes.length > 0) {
|
||||
let newNodes = createNodes(contentTypes, options);
|
||||
setNodes(newNodes);
|
||||
if (options.showEdges) {
|
||||
let newEdges = createEdegs(contentTypes, options);
|
||||
setEdges(newEdges);
|
||||
} else {
|
||||
setEdges([]);
|
||||
}
|
||||
}
|
||||
}, [contentTypes, options]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<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"
|
||||
>
|
||||
Help
|
||||
</LinkButton>
|
||||
}
|
||||
/>
|
||||
<OptionsBar options={options} toggleOption={toggleOption} />
|
||||
<div
|
||||
style={{
|
||||
height: "100vh",
|
||||
borderTop: `1px solid ${theme.colors.neutral150}`,
|
||||
}}
|
||||
>
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
onNodesChange={onNodesChange}
|
||||
onEdgesChange={onEdgesChange}
|
||||
onConnect={onConnect}
|
||||
nodeTypes={nodeTypes}
|
||||
edgeTypes={edgeTypes}
|
||||
fitView
|
||||
minZoom={0}
|
||||
preventScrolling={!options.scrollMode}
|
||||
snapGrid={[20, 20]}
|
||||
snapToGrid={options.snapToGrid}
|
||||
fitViewOptions={{
|
||||
maxZoom: 1,
|
||||
}}
|
||||
>
|
||||
<Controls
|
||||
position="top-left"
|
||||
showInteractive={false}
|
||||
className="cte-plugin-controls"
|
||||
style={{
|
||||
"--button-background": theme.colors.neutral150,
|
||||
"--button-foreground": theme.colors.neutral1000,
|
||||
"--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>
|
||||
</Controls>
|
||||
<Background
|
||||
variant={options.backgroundPattern}
|
||||
color={getBackgroundColor(options.backgroundPattern, theme)}
|
||||
/>
|
||||
</ReactFlow>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default HomePage;
|
|
@ -0,0 +1,12 @@
|
|||
.cte-plugin-controls button {
|
||||
background-color: var(--button-background);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.cte-plugin-controls button:hover {
|
||||
background-color: var(--button-hover);
|
||||
}
|
||||
|
||||
.cte-plugin-controls button svg {
|
||||
fill: var(--button-foreground);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import pluginPkg from '../../package.json';
|
||||
|
||||
const pluginId = pluginPkg.name.replace(/^(@[^-,.][\w,-]+\/|strapi-)plugin-/i, '');
|
||||
|
||||
export default pluginId;
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -0,0 +1,54 @@
|
|||
const CARDS_PER_ROW = 6;
|
||||
|
||||
export function createNodes(contentTypes, options) {
|
||||
let newNodes = [];
|
||||
contentTypes.map(
|
||||
(node, index) =>
|
||||
(newNodes = [
|
||||
...newNodes,
|
||||
{
|
||||
id: node.key,
|
||||
position: {
|
||||
x: (index % CARDS_PER_ROW) * 320,
|
||||
y: ((index - (index % CARDS_PER_ROW)) / CARDS_PER_ROW) * 560,
|
||||
},
|
||||
type: "special",
|
||||
|
||||
data: {
|
||||
...node,
|
||||
options: options,
|
||||
},
|
||||
},
|
||||
])
|
||||
);
|
||||
return newNodes;
|
||||
}
|
||||
|
||||
export function createEdegs(contentTypes, options) {
|
||||
let newEdges = [];
|
||||
|
||||
contentTypes.map((contentType) => {
|
||||
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
|
||||
)
|
||||
) {
|
||||
newEdges = [
|
||||
...newEdges,
|
||||
{
|
||||
id: `${contentType.attributes[attr].target}-${contentType.key}.${attr}`,
|
||||
source: contentType.key,
|
||||
target: contentType.attributes[attr].target,
|
||||
type: options.edgeType,
|
||||
sourceHandle: attr,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return newEdges;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import pluginId from '../pluginId';
|
||||
|
||||
const getTrad = (id) => `${pluginId}.${id}`;
|
||||
|
||||
export default getTrad;
|
|
@ -0,0 +1,86 @@
|
|||
import React from "react";
|
||||
import { darkTheme } from "@strapi/design-system";
|
||||
|
||||
import {
|
||||
Text,
|
||||
Email,
|
||||
Password,
|
||||
Number,
|
||||
Enumeration,
|
||||
Date,
|
||||
Media,
|
||||
Boolean,
|
||||
Json,
|
||||
Relation,
|
||||
Uid,
|
||||
OneToMany,
|
||||
OneToOne,
|
||||
ManyToMany,
|
||||
ManyToOne,
|
||||
OneWay,
|
||||
ManyWays,
|
||||
RichText,
|
||||
} from "@strapi/icons";
|
||||
|
||||
export function getBackgroundColor(variant, theme) {
|
||||
switch (variant) {
|
||||
case "cross":
|
||||
return theme.colors.neutral200;
|
||||
case "dots":
|
||||
return darkTheme.colors.neutral300;
|
||||
case "lines":
|
||||
return theme.colors.neutral150;
|
||||
case "none":
|
||||
return theme.colors.neutral100;
|
||||
}
|
||||
}
|
||||
|
||||
export function getIcon(attrType) {
|
||||
switch (attrType.toLowerCase()) {
|
||||
case "string":
|
||||
case "text":
|
||||
return <Text />;
|
||||
case "email":
|
||||
return <Email />;
|
||||
case "enumeration":
|
||||
return <Enumeration />;
|
||||
case "password":
|
||||
return <Password />;
|
||||
case "boolean":
|
||||
return <Boolean />;
|
||||
case "relation":
|
||||
return <Relation />;
|
||||
case "datetime":
|
||||
case "date":
|
||||
case "time":
|
||||
return <Date />;
|
||||
case "integer":
|
||||
case "decimal":
|
||||
case "biginteger":
|
||||
case "float":
|
||||
return <Number />;
|
||||
case "json":
|
||||
return <Json />;
|
||||
case "uid":
|
||||
return <Uid />;
|
||||
case "richtext":
|
||||
return <RichText />;
|
||||
case "media":
|
||||
return <Media />;
|
||||
|
||||
case "onetomany": //
|
||||
return <OneToMany />;
|
||||
case "oneway":
|
||||
return <OneWay />;
|
||||
case "onetoone": //
|
||||
return <OneToOne />;
|
||||
case "manytomany": //
|
||||
return <ManyToMany />;
|
||||
case "manytoone": //
|
||||
return <ManyToOne />;
|
||||
case "manyways":
|
||||
// Not sure
|
||||
case "morphtomany":
|
||||
return <ManyWays />;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"name": "content-type-explorer",
|
||||
"version": "0.0.0",
|
||||
"description": "This is the description of the plugin.",
|
||||
"strapi": {
|
||||
"name": "content-type-explorer",
|
||||
"description": "Description of Content Type Explorer plugin",
|
||||
"kind": "plugin",
|
||||
"displayName": "Content Type Explorer"
|
||||
},
|
||||
"dependencies": {
|
||||
"@strapi/design-system": "^1.6.3",
|
||||
"@strapi/helper-plugin": "^4.6.0",
|
||||
"@strapi/icons": "^1.6.3",
|
||||
"prop-types": "^15.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^5.3.4",
|
||||
"styled-components": "^5.3.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0",
|
||||
"react-router-dom": "^5.3.4",
|
||||
"styled-components": "^5.3.6"
|
||||
},
|
||||
"author": {
|
||||
"name": "A Strapi developer"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "A Strapi developer"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.19.1 <=18.x.x",
|
||||
"npm": ">=6.0.0"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = ({ strapi }) => {
|
||||
// bootstrap phase
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
default: {},
|
||||
validator() {},
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {};
|
|
@ -0,0 +1,20 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = ({ strapi }) => ({
|
||||
getContentTypes(ctx) {
|
||||
const data = strapi
|
||||
.plugin("content-type-explorer")
|
||||
.service("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;
|
||||
},
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
const explorerController = require("./explorer-controller");
|
||||
|
||||
module.exports = {
|
||||
explorerController,
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = ({ strapi }) => {
|
||||
// destroy phase
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
'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');
|
||||
|
||||
module.exports = {
|
||||
register,
|
||||
bootstrap,
|
||||
destroy,
|
||||
config,
|
||||
controllers,
|
||||
routes,
|
||||
services,
|
||||
contentTypes,
|
||||
policies,
|
||||
middlewares,
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {};
|
|
@ -0,0 +1,3 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {};
|
|
@ -0,0 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = ({ strapi }) => {
|
||||
// registeration phase
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
module.exports = [
|
||||
{
|
||||
method: "GET",
|
||||
path: "/get-content-types",
|
||||
handler: "explorerController.getContentTypes",
|
||||
config: {
|
||||
policies: [],
|
||||
},
|
||||
},
|
||||
];
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = ({ strapi }) => ({
|
||||
getContentTypes() {
|
||||
return strapi.contentTypes;
|
||||
},
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
const explorerService = require("./explorer-service");
|
||||
|
||||
module.exports = {
|
||||
explorerService,
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = require('./admin/src').default;
|
|
@ -0,0 +1,3 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = require('./server');
|
Loading…
Reference in New Issue