update folder structure

pull/5/head
ShahriarKh 2023-07-14 02:52:55 +03:30
parent ed7e6f31b9
commit eac565f0cd
35 changed files with 448 additions and 449 deletions

View File

@ -1 +1,3 @@
# strapi-content-type-explorer
# Strapi plugin content-type-explorer
A quick description of content-type-explorer.

View File

@ -1,11 +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;
import { request } from "@strapi/helper-plugin";
const explorerRequests = {
getContentTypes: async () => {
return await request("/content-type-explorer/get-content-types", {
method: "GET",
});
},
};
export default explorerRequests;

View File

@ -1,35 +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;
}
.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;
}

View File

@ -1,116 +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>
);
}
/**
*
* 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>
);
}

View File

@ -1,110 +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>
);
}
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>
);
}

View File

@ -1,21 +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};
}
`;
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};
}
`;

View File

@ -1,12 +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);
}
.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);
}

View File

@ -1,54 +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;
}
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;
}

View File

@ -1,86 +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 />;
}
}
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 />;
}
}

View File

@ -1,3 +0,0 @@
# Strapi plugin content-type-explorer
A quick description of content-type-explorer.