mirror of https://github.com/ctk-hq/ctk
feat: yaml importing
parent
a0d456079b
commit
f37c271581
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.0.4 on 2022-08-04 06:25
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('api', '0002_project_uuid'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='project',
|
||||||
|
name='visibility',
|
||||||
|
field=models.SmallIntegerField(default='1'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
import * as yup from "yup";
|
||||||
|
|
||||||
|
export interface IImportForm {
|
||||||
|
url: string;
|
||||||
|
visibility: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IImportFinalValues {
|
||||||
|
url: string;
|
||||||
|
visibility: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialValues: IImportForm = {
|
||||||
|
url: "",
|
||||||
|
visibility: []
|
||||||
|
};
|
||||||
|
|
||||||
|
export const validationSchema = yup.object({
|
||||||
|
url: yup
|
||||||
|
.string()
|
||||||
|
.max(256, "url should be 500 characters or less")
|
||||||
|
.required("url is required")
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getInitialValues = (values?: any): IImportForm => {
|
||||||
|
if (!values) {
|
||||||
|
return {
|
||||||
|
...initialValues
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { url, visibility } = values;
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: url ?? (initialValues.url as string),
|
||||||
|
visibility: visibility ?? []
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getFinalValues = (values: IImportForm): IImportFinalValues => {
|
||||||
|
const { url, visibility } = values;
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: url ?? "",
|
||||||
|
visibility: visibility.length ? 1 : 0
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,115 @@
|
|||||||
|
import { useCallback, useMemo, useState } from "react";
|
||||||
|
import { Field, Formik } from "formik";
|
||||||
|
import { styled } from "@mui/joy";
|
||||||
|
import { XIcon } from "@heroicons/react/outline";
|
||||||
|
import { CallbackFunction } from "../../../types";
|
||||||
|
import { IImportForm } from "./form-utils";
|
||||||
|
import {
|
||||||
|
getFinalValues,
|
||||||
|
getInitialValues,
|
||||||
|
validationSchema
|
||||||
|
} from "./form-utils";
|
||||||
|
import TextField from "../../global/FormElements/TextField";
|
||||||
|
import { toaster } from "../../../utils";
|
||||||
|
import { reportErrorsAndSubmit } from "../../../utils/forms";
|
||||||
|
import { ScrollView } from "../../ScrollView";
|
||||||
|
import lodash from "lodash";
|
||||||
|
|
||||||
|
interface IModalImportProps {
|
||||||
|
onHide: CallbackFunction;
|
||||||
|
onImport: CallbackFunction;
|
||||||
|
importing: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FormContainer = styled("div")`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ModalImport = (props: IModalImportProps) => {
|
||||||
|
const { onHide, onImport, importing } = props;
|
||||||
|
|
||||||
|
const handleCreate = useCallback(
|
||||||
|
(values: IImportForm, formik: any) => {
|
||||||
|
const result = getFinalValues(values);
|
||||||
|
onImport(result);
|
||||||
|
toaster(`Importing...`, "success");
|
||||||
|
},
|
||||||
|
[onImport, onHide]
|
||||||
|
);
|
||||||
|
|
||||||
|
const initialValues = useMemo(() => getInitialValues(), []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed z-50 inset-0 overflow-y-auto">
|
||||||
|
<div className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 outline-none focus:outline-none">
|
||||||
|
<div
|
||||||
|
onClick={onHide}
|
||||||
|
className="opacity-25 fixed inset-0 z-40 bg-black"
|
||||||
|
></div>
|
||||||
|
<div className="relative w-auto my-6 mx-auto max-w-5xl z-50">
|
||||||
|
<div className="border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-white outline-none focus:outline-none">
|
||||||
|
<div className="flex items-center justify-between px-4 py-3 border-b border-solid border-blueGray-200 rounded-t">
|
||||||
|
<h3 className="text-sm font-semibold">Import</h3>
|
||||||
|
<button
|
||||||
|
className="p-1 ml-auto text-black float-right outline-none focus:outline-none"
|
||||||
|
onClick={onHide}
|
||||||
|
>
|
||||||
|
<span className="block outline-none focus:outline-none">
|
||||||
|
<XIcon className="w-4" />
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Formik
|
||||||
|
initialValues={initialValues}
|
||||||
|
enableReinitialize={true}
|
||||||
|
onSubmit={handleCreate}
|
||||||
|
validationSchema={validationSchema}
|
||||||
|
>
|
||||||
|
{(formik) => (
|
||||||
|
<FormContainer>
|
||||||
|
<div>
|
||||||
|
<ScrollView
|
||||||
|
className="relative px-4 py-3 flex-auto"
|
||||||
|
height={""}
|
||||||
|
>
|
||||||
|
<TextField label="yaml url" name="url" required={true} />
|
||||||
|
|
||||||
|
<label htmlFor="visibility" className="lbl-util">
|
||||||
|
Visibility
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
id="visibility"
|
||||||
|
name="visibility"
|
||||||
|
className="checkbox-util"
|
||||||
|
type="checkbox"
|
||||||
|
onChange={formik.handleChange}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{importing && <>importing</>}
|
||||||
|
</ScrollView>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-end px-4 py-3 border-t border-solid border-blueGray-200 rounded-b">
|
||||||
|
<button
|
||||||
|
className="btn-util"
|
||||||
|
type="button"
|
||||||
|
onClick={reportErrorsAndSubmit(formik)}
|
||||||
|
>
|
||||||
|
Import
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</FormContainer>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ModalImport;
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import { EyeIcon, EyeOffIcon } from "@heroicons/react/solid";
|
||||||
|
import { CallbackFunction } from "../../../types";
|
||||||
|
|
||||||
|
interface IVisibilitySwitchProps {
|
||||||
|
onToggle: CallbackFunction;
|
||||||
|
isVisible: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VisibilitySwitch = (props: IVisibilitySwitchProps) => {
|
||||||
|
const { isVisible, onToggle } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex items-center justify-end">
|
||||||
|
<button
|
||||||
|
onClick={onToggle}
|
||||||
|
id="theme-toggle"
|
||||||
|
type="button"
|
||||||
|
className="
|
||||||
|
btn-util
|
||||||
|
bg-white
|
||||||
|
focus:ring-0
|
||||||
|
text-gray-500
|
||||||
|
hover:bg-white
|
||||||
|
hover:text-gray-800
|
||||||
|
focus:outline-none
|
||||||
|
text-sm"
|
||||||
|
>
|
||||||
|
{isVisible ? (
|
||||||
|
<EyeIcon id="theme-toggle-light-icon" className="w-5 h-5" />
|
||||||
|
) : (
|
||||||
|
<EyeOffIcon id="theme-toggle-dark-icon" className="w-5 h-5" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VisibilitySwitch;
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { IImportFinalValues } from "../components/Modal/import/form-utils";
|
||||||
|
import { API_SERVER_URL } from "../constants";
|
||||||
|
import { getLocalStorageJWTKeys } from "../utils";
|
||||||
|
|
||||||
|
export const importProject = async (values: IImportFinalValues) => {
|
||||||
|
const jwtKeys = getLocalStorageJWTKeys();
|
||||||
|
const response = await axios({
|
||||||
|
method: "post",
|
||||||
|
url: `${API_SERVER_URL}/projects/import/`,
|
||||||
|
data: { ...values },
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Bearer ${jwtKeys.access_token}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue