|
|
|
@ -1,45 +1,45 @@
|
|
|
|
import { useEffect, useState } from "react";
|
|
|
|
import { useEffect, useState } from "react"
|
|
|
|
import { useParams, useNavigate } from "react-router-dom";
|
|
|
|
import { useParams, useNavigate } from "react-router-dom"
|
|
|
|
import { IProjectPayload } from "../../types";
|
|
|
|
import { IProjectPayload } from "../../types"
|
|
|
|
import { nodes, connections, position, updateProjectName } from "../../reducers";
|
|
|
|
import { nodes, connections, position, updateProjectName } from "../../reducers"
|
|
|
|
import Spinner from "../Spinner";
|
|
|
|
import Spinner from "../Spinner"
|
|
|
|
import { Canvas } from "../Canvas";
|
|
|
|
import { Canvas } from "../Canvas"
|
|
|
|
import useWindowDimensions from "../../hooks/useWindowDimensions";
|
|
|
|
import useWindowDimensions from "../../hooks/useWindowDimensions"
|
|
|
|
import { getClientNodesAndConnections } from "../../utils";
|
|
|
|
import { getClientNodesAndConnections } from "../../utils"
|
|
|
|
import { projectHttpGet, projectHttpUpdate, projectHttpCreate } from "../../services/project";
|
|
|
|
import {
|
|
|
|
import { checkHttpStatus } from "../../services/helpers";
|
|
|
|
projectHttpGet,
|
|
|
|
import { nodeLibraries } from "../../utils/data/libraries";
|
|
|
|
projectHttpUpdate,
|
|
|
|
|
|
|
|
projectHttpCreate
|
|
|
|
|
|
|
|
} from "../../services/project"
|
|
|
|
|
|
|
|
import { checkHttpStatus } from "../../services/helpers"
|
|
|
|
|
|
|
|
import { nodeLibraries } from "../../utils/data/libraries"
|
|
|
|
|
|
|
|
|
|
|
|
interface IProjectProps {
|
|
|
|
interface IProjectProps {
|
|
|
|
dispatch: any;
|
|
|
|
dispatch: any
|
|
|
|
state: any;
|
|
|
|
state: any
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default function Project(props: IProjectProps) {
|
|
|
|
export default function Project(props: IProjectProps) {
|
|
|
|
const { uuid } = useParams<{ uuid?: string }>();
|
|
|
|
const { uuid } = useParams<{ uuid?: string }>()
|
|
|
|
const { dispatch, state } = props;
|
|
|
|
const { dispatch, state } = props
|
|
|
|
const [saving, setSaving] = useState(false);
|
|
|
|
const [saving, setSaving] = useState(false)
|
|
|
|
const [projectName, setProjectName] = useState("");
|
|
|
|
const [projectName, setProjectName] = useState("")
|
|
|
|
const { height, width } = useWindowDimensions();
|
|
|
|
const { height, width } = useWindowDimensions()
|
|
|
|
const navigate = useNavigate();
|
|
|
|
const navigate = useNavigate()
|
|
|
|
|
|
|
|
|
|
|
|
const handleNameChange = (e: any) => {
|
|
|
|
const handleNameChange = (e: any) => {
|
|
|
|
setProjectName(e.target.value);
|
|
|
|
setProjectName(e.target.value)
|
|
|
|
dispatch(updateProjectName(e.target.value));
|
|
|
|
dispatch(updateProjectName(e.target.value))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const updateProject = (uuid: string, payload: IProjectPayload) => {
|
|
|
|
const updateProject = (uuid: string, payload: IProjectPayload) => {
|
|
|
|
projectHttpUpdate(uuid, JSON.stringify(payload))
|
|
|
|
projectHttpUpdate(uuid, JSON.stringify(payload))
|
|
|
|
.then(checkHttpStatus)
|
|
|
|
.then(checkHttpStatus)
|
|
|
|
.then(data => {
|
|
|
|
.then(data => {})
|
|
|
|
|
|
|
|
.catch(err => {})
|
|
|
|
})
|
|
|
|
|
|
|
|
.catch(err => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.finally(() => {
|
|
|
|
.finally(() => {
|
|
|
|
setSaving(false);
|
|
|
|
setSaving(false)
|
|
|
|
});
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const createProject = (payload: IProjectPayload) => {
|
|
|
|
const createProject = (payload: IProjectPayload) => {
|
|
|
|
@ -48,16 +48,14 @@ export default function Project(props: IProjectProps) {
|
|
|
|
.then(data => {
|
|
|
|
.then(data => {
|
|
|
|
navigate(`/projects/${data.uuid}`)
|
|
|
|
navigate(`/projects/${data.uuid}`)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.catch(err => {
|
|
|
|
.catch(err => {})
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.finally(() => {
|
|
|
|
.finally(() => {
|
|
|
|
setSaving(false);
|
|
|
|
setSaving(false)
|
|
|
|
});
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const onSave = () => {
|
|
|
|
const onSave = () => {
|
|
|
|
setSaving(true);
|
|
|
|
setSaving(true)
|
|
|
|
const payload: IProjectPayload = {
|
|
|
|
const payload: IProjectPayload = {
|
|
|
|
name: state.projectName,
|
|
|
|
name: state.projectName,
|
|
|
|
data: {
|
|
|
|
data: {
|
|
|
|
@ -71,66 +69,75 @@ export default function Project(props: IProjectProps) {
|
|
|
|
secrets: [],
|
|
|
|
secrets: [],
|
|
|
|
services: state.nodes,
|
|
|
|
services: state.nodes,
|
|
|
|
version: 3,
|
|
|
|
version: 3,
|
|
|
|
volumes: [],
|
|
|
|
volumes: []
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (uuid) {
|
|
|
|
if (uuid) {
|
|
|
|
updateProject(uuid, payload);
|
|
|
|
updateProject(uuid, payload)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
createProject(payload);
|
|
|
|
createProject(payload)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const setViewHeight = () => {
|
|
|
|
const setViewHeight = () => {
|
|
|
|
let vh = window.innerHeight * 0.01;
|
|
|
|
let vh = window.innerHeight * 0.01
|
|
|
|
document.documentElement.style.setProperty('--vh', `${vh}px`);
|
|
|
|
document.documentElement.style.setProperty("--vh", `${vh}px`)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const { data, error, isFetching } = useProject(uuid)
|
|
|
|
if (uuid) {
|
|
|
|
|
|
|
|
projectHttpGet(uuid)
|
|
|
|
const { nodesAsList, clientNodeItems } = useMemo(() => {
|
|
|
|
.then(checkHttpStatus)
|
|
|
|
if (!data) {
|
|
|
|
.then(data => {
|
|
|
|
return
|
|
|
|
const projectData = JSON.parse(data.data);
|
|
|
|
|
|
|
|
const nodesAsList = Object.keys(projectData.canvas.nodes).map((k) => {
|
|
|
|
|
|
|
|
return projectData.canvas.nodes[k];
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const clientNodeItems = getClientNodesAndConnections(nodesAsList, nodeLibraries);
|
|
|
|
|
|
|
|
setProjectName(data.name);
|
|
|
|
|
|
|
|
dispatch(updateProjectName(data.name));
|
|
|
|
|
|
|
|
dispatch(nodes(clientNodeItems));
|
|
|
|
|
|
|
|
dispatch(connections(projectData.canvas.connections));
|
|
|
|
|
|
|
|
dispatch(position(projectData.canvas.position));
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.catch(err => {
|
|
|
|
|
|
|
|
if (err.status === 404) {
|
|
|
|
|
|
|
|
window.location.replace("/");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
|
|
//setFetching(false);
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, [uuid, dispatch]);
|
|
|
|
|
|
|
|
|
|
|
|
const nodesAsList = Object.keys(projectData.canvas.nodes).map(k => {
|
|
|
|
|
|
|
|
return projectData.canvas.nodes[k]
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const clientNodeItems = getClientNodesAndConnections(
|
|
|
|
|
|
|
|
nodesAsList,
|
|
|
|
|
|
|
|
nodeLibraries
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* TODO: Remove these dispatch calls as we migrate other components
|
|
|
|
|
|
|
|
* to React Query.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
dispatch(updateProjectName(data.name));
|
|
|
|
|
|
|
|
dispatch(nodes(clientNodeItems));
|
|
|
|
|
|
|
|
dispatch(connections(projectData.canvas.connections));
|
|
|
|
|
|
|
|
dispatch(position(projectData.canvas.position));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return { nodesAsList, clientNodeItems }
|
|
|
|
|
|
|
|
}, [dispatch])
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
useEffect(() => {
|
|
|
|
//setProjectName(state.projectName);
|
|
|
|
if (uuid && !isFetching && data) {
|
|
|
|
}, [state.projectName]);
|
|
|
|
setProjectName(data.name)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}, [uuid, isFetching, data?.name])
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
useEffect(() => {
|
|
|
|
window.addEventListener("resize", () => {
|
|
|
|
const handler = () => {
|
|
|
|
setViewHeight();
|
|
|
|
setViewHeight()
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setViewHeight();
|
|
|
|
window.addEventListener("resize", handler)
|
|
|
|
}, []);
|
|
|
|
setViewHeight()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
() => {
|
|
|
|
|
|
|
|
window.removeEventListener("resize", handler)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<>
|
|
|
|
<div className="px-4 py-3 border-b border-gray-200">
|
|
|
|
<div className="px-4 py-3 border-b border-gray-200">
|
|
|
|
<form className="flex flex-col space-y-2 md:flex-row md:justify-between items-center" autoComplete="off">
|
|
|
|
<form
|
|
|
|
|
|
|
|
className="flex flex-col space-y-2 md:flex-row md:justify-between items-center"
|
|
|
|
|
|
|
|
autoComplete="off"
|
|
|
|
|
|
|
|
>
|
|
|
|
<input
|
|
|
|
<input
|
|
|
|
className={`
|
|
|
|
className={`
|
|
|
|
bg-gray-100
|
|
|
|
bg-gray-100
|
|
|
|
@ -165,7 +172,7 @@ export default function Project(props: IProjectProps) {
|
|
|
|
<div className="flex flex-col space-y-2 w-full justify-end mb-4 md:flex-row md:space-y-0 md:space-x-2 md:mb-0">
|
|
|
|
<div className="flex flex-col space-y-2 w-full justify-end mb-4 md:flex-row md:space-y-0 md:space-x-2 md:mb-0">
|
|
|
|
<button
|
|
|
|
<button
|
|
|
|
onClick={() => {
|
|
|
|
onClick={() => {
|
|
|
|
window.location.replace("/");
|
|
|
|
window.location.replace("/")
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
type="button"
|
|
|
|
type="button"
|
|
|
|
className="btn-util text-black bg-gray-200 hover:bg-gray-300 sm:w-auto"
|
|
|
|
className="btn-util text-black bg-gray-200 hover:bg-gray-300 sm:w-auto"
|
|
|
|
@ -181,9 +188,7 @@ export default function Project(props: IProjectProps) {
|
|
|
|
className="btn-util text-white bg-green-600 hover:bg-green-700 sm:w-auto"
|
|
|
|
className="btn-util text-white bg-green-600 hover:bg-green-700 sm:w-auto"
|
|
|
|
>
|
|
|
|
>
|
|
|
|
<div className="flex justify-center items-center space-x-2 mx-auto">
|
|
|
|
<div className="flex justify-center items-center space-x-2 mx-auto">
|
|
|
|
{saving &&
|
|
|
|
{saving && <Spinner className="w-4 h-4 text-green-300" />}
|
|
|
|
<Spinner className="w-4 h-4 text-green-300" />
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
<span>Save</span>
|
|
|
|
<span>Save</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</button>
|
|
|
|
</button>
|
|
|
|
@ -192,12 +197,8 @@ export default function Project(props: IProjectProps) {
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="flex flex-grow relative flex-col md:flex-row">
|
|
|
|
<div className="flex flex-grow relative flex-col md:flex-row">
|
|
|
|
<Canvas
|
|
|
|
<Canvas state={state} dispatch={dispatch} height={height - 64} />
|
|
|
|
state={state}
|
|
|
|
|
|
|
|
dispatch={dispatch}
|
|
|
|
|
|
|
|
height={(height - 64)}
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|