Skip to content

Commit

Permalink
feat(host-directories): 🎉 add selectable logic at cf-advanced-settings
Browse files Browse the repository at this point in the history
  • Loading branch information
gokhangunduz committed Dec 26, 2023
1 parent 0ba0b89 commit 1028c6b
Show file tree
Hide file tree
Showing 15 changed files with 287 additions and 102 deletions.
9 changes: 9 additions & 0 deletions public/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -1766,6 +1766,10 @@ video {
border-radius: 0.375rem;
}

.rounded-sm {
border-radius: 0.125rem;
}

.rounded-l-lg {
border-top-left-radius: 0.5rem;
border-bottom-left-radius: 0.5rem;
Expand Down Expand Up @@ -3373,6 +3377,11 @@ td {
--tw-ring-color: rgb(204 126 254 / var(--tw-ring-opacity));
}

.focus\:ring-primary-500:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(172 45 254 / var(--tw-ring-opacity));
}

.active\:scale-75:active {
--tw-scale-x: .75;
--tw-scale-y: .75;
Expand Down
14 changes: 7 additions & 7 deletions src/components/CFAdvancedSettings/CFAdvancedSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import CFHostDirectories2 from "../CFHostDirectories2/CFHostDirectories2";
// import CFDirectories from "../CFHostDirectories/CFHostDirectories";
import CFPersistDirTags from "../CFPersistDirTags/CFPersistDirTags";
import CFGrantDirTags from "../CFGrantDirTags/CFGrantDirTags";
import { IDetails } from "../../interfaces/robotInterfaces";
Expand All @@ -7,8 +9,6 @@ import { FormikProps } from "formik/dist/types";
import { ReactElement, useState } from "react";
import CFSection from "../CFSection/CFSection";
import Seperator from "../Seperator/Seperator";
import CFHostDirectories2 from "../CFHostDirectories2/CFHostDirectories2";
// import CFHostDirectories from "../CFHostDirectories/CFHostDirectories";

interface ICFAdvancedSettings {
formik: FormikProps<IDetails>;
Expand All @@ -32,11 +32,6 @@ export default function CFAdvancedSettings({
}}
>
<div className="flex flex-col gap-8 px-4 pb-6 pt-2">
{/* <CFSection>
<CFHostDirectories />
<Seperator />
</CFSection> */}

<CFSection gap={4}>
<CFPersistDirTags formik={formik} disabled={disabled} />
<Seperator />
Expand All @@ -47,6 +42,11 @@ export default function CFAdvancedSettings({
<Seperator />
</CFSection>

{/* <CFSection gap={4}>
<CFDirectories formik={formik} disabled={disabled} />
<Seperator />
</CFSection> */}

<CFSection gap={4}>
<CFHostDirectories2 formik={formik} disabled={disabled} />
<Seperator />
Expand Down
6 changes: 3 additions & 3 deletions src/components/CFDellButton/CFDellButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { ReactElement } from "react";
import { IoTrashBinOutline } from "react-icons/io5";
import { ReactElement } from "react";
import { MdRemoveCircleOutline } from "react-icons/md";

interface ICFDellButton {
disabled?: boolean;
Expand All @@ -16,7 +16,7 @@ export default function CFDellButton({
onClick={onClick}
className="transition-300 hover:scale-90"
>
<IoTrashBinOutline color={disabled ? "gray" : "red"} size={18} />
<MdRemoveCircleOutline color={disabled ? "gray" : "red"} size={18} />
</button>
);
}
119 changes: 119 additions & 0 deletions src/components/CFDirectoriesSelectInput/CFDirectoriesSelectInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { IDetails } from "../../interfaces/robotInterfaces";
import { ReactElement, useEffect, useState } from "react";
import useFunctions from "../../hooks/useFunctions";
import InputError from "../InputError/InputError";
import InfoTip from "../InfoTip/InfoTip";
import { FormikProps } from "formik";
import Select from "react-select";

interface ICFDirectoriesSelectInput {
type?: "host" | "mount";
formik: FormikProps<IDetails>;
index?: number;
dataTut?: string;
labelName?: string;
labelInfoTip?: string;
rightTip?: boolean;
classNameContainer?: string;
classNameInput?: string;
inputError?: string;
inputTouched?: boolean;
}

export default function CFDirectoriesSelectInput({
type,
formik,
index,
dataTut,
labelName,
labelInfoTip,
rightTip,
classNameContainer,
classNameInput,
inputError,
inputTouched,
}: ICFDirectoriesSelectInput): ReactElement {
const [selectableItems, setSelectableItems] = useState<string[]>([]);
const [selectedItems, setSelectedItems] = useState<string[]>([]);
const [menuIsOpen, setMenuIsOpen] = useState<boolean>(false);
const { getFiles } = useFunctions();

useEffect(() => {
console.log("selectableItems", selectableItems);
console.log("selectedItems", selectedItems);
}, [selectableItems, selectedItems]);

useEffect(() => {
if (type === "host") {
formik.setFieldValue(
`hostDirectories.[${index}].hostDirectory`,
selectedItems?.join(""),
);
} else {
formik.setFieldValue(
`hostDirectories.[${index}].mountPath`,
selectedItems?.join(""),
);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [index, selectedItems, type]);

async function handleGetSelectableItems(paths?: string[]) {
const { items } = await getFiles(paths);

if (items?.length) {
setSelectableItems(
items
?.filter((item: any) => item.isDir)
?.map((item: any) => `/${item.name}`),
);
} else {
setSelectableItems([]);
setMenuIsOpen(false);
}
}

return (
<div data-tut={dataTut} className={classNameContainer}>
<div
className={`flex min-w-fit gap-1 pb-3 text-xs font-medium text-light-700 ${classNameInput}`}
>
{labelName}
<InfoTip content={labelInfoTip} rightTip={rightTip} />
</div>
<Select
menuIsOpen={menuIsOpen}
options={
selectableItems?.map((item) => ({
value: item,
label: selectedItems?.join() + item,
})) ?? []
}
onMenuOpen={() => {
handleGetSelectableItems(selectedItems);
setMenuIsOpen(true);
}}
onBlur={() => setMenuIsOpen(false)}
onChange={(selected) => {
if (selected) {
setSelectedItems([...selectedItems, selected.value]);
handleGetSelectableItems([...selectedItems, selected.value]);
setMenuIsOpen(true);
} else {
setSelectedItems([]);
handleGetSelectableItems();
}
console.log(selected);
}}
maxMenuHeight={160}
isSearchable
isClearable
className="text-xs"
classNamePrefix="text-xs"
placeholder="Select a directory..."
required
/>
<InputError error={inputError} touched={inputTouched} />
</div>
);
}
100 changes: 45 additions & 55 deletions src/components/CFHostDirectories/CFHostDirectories.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,52 @@
import { ReactElement, useEffect, useState } from "react";
import useFunctions from "../../hooks/useFunctions";
import Select from "react-select";
import { ReactElement } from "react";
import CFDirectoriesInputGroup from "../CFHostDirectoriesInputGroup/CFHostDirectoriesInputGroup";
import CFInfoBar from "../CFInfoBar/CFInfoBar";
import CreateRobotFormAddButton from "../CreateRobotFormAddButton/CreateRobotFormAddButton";
import { FormikProps } from "formik";
import { IDetails } from "../../interfaces/robotInterfaces";

export default function CFHostDirectories(): ReactElement {
const [menuIsOpen, setMenuIsOpen] = useState<boolean>(false);
const [selectableItems, setSelectableItems] = useState<string[]>([]);
const [selectedItems, setSelectedItems] = useState<string[]>([]);
const { getFiles } = useFunctions();

useEffect(() => {
handleGetSelectableItems();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
console.log("selectableItems", selectableItems);
console.log("selectedItems", selectedItems);
}, [selectableItems, selectedItems]);

async function handleGetSelectableItems(paths?: string[]) {
const { items } = await getFiles(paths || []);

if (items?.length) {
setSelectableItems(
items
?.filter((item: any) => item.isDir)
?.map((item: any) => `/${item.name}`),
);
} else {
setSelectableItems([]);
setMenuIsOpen(false);
}
}
interface ICFDirectories {
formik: FormikProps<IDetails>;
disabled?: boolean;
}

export default function CFDirectories({
formik,
disabled,
}: ICFDirectories): ReactElement {
return (
<>
<Select
menuIsOpen={menuIsOpen}
options={
selectableItems?.map((item) => ({
value: item,
label: selectedItems?.join("") || item,
})) || []
}
onChange={(e) => {
if (e) {
handleGetSelectableItems([...selectedItems, e.value]);
setSelectedItems([...selectedItems, e.value]);
}
}}
onFocus={() => setMenuIsOpen(true)}
onBlur={() => setMenuIsOpen(false)}
value={{
value: selectedItems?.join("") || "",
label: selectedItems?.join("") || "",
<div>
<CFInfoBar
label="Host Directories:"
tip="You can link a directory on the host to the directory specified in the application here."
vertical
>
<div className="flex flex-col gap-2">
{formik.values.hostDirectories?.map((_, index) => {
return (
<CFDirectoriesInputGroup
key={index}
formik={formik}
disabled={disabled}
index={index}
/>
);
})}
</div>
</CFInfoBar>

<CreateRobotFormAddButton
onClick={() => {
formik.setFieldValue("hostDirectories", [
...formik.values.hostDirectories,
{
hostDirectory: "",
mountPath: "",
},
]);
}}
isClearable
disabled={disabled}
/>
</>
</div>
);
}
2 changes: 1 addition & 1 deletion src/components/CFHostDirectories2/CFHostDirectories2.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import CreateRobotFormAddButton from "../CreateRobotFormAddButton/CreateRobotFormAddButton";
import CFHostDirectoriesInput from "../CFHostDirectoriesInput/CFHostDirectoriesInput";
import CFHostDirectoriesInput from "../CFHostDirectoriesInput2/CFHostDirectoriesInput2";
import { IDetails } from "../../interfaces/robotInterfaces";
import { FormikProps } from "formik/dist/types";
import CFInfoBar from "../CFInfoBar/CFInfoBar";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import CFDirectoriesSelectInput from "../CFDirectoriesSelectInput/CFDirectoriesSelectInput";
import { IDetails } from "../../interfaces/robotInterfaces";
import CFDellButton from "../CFDellButton/CFDellButton";
import { ReactElement } from "react";
import { FormikProps } from "formik";

interface ICFDirectoriesInputGroup {
formik: FormikProps<IDetails>;
disabled?: boolean;
index: number;
}

export default function CFDirectoriesInputGroup({
formik,
disabled,
index,
}: ICFDirectoriesInputGroup): ReactElement {
return (
<div className="flex w-full gap-4 rounded-md border border-light-100 p-4 shadow-sm">
<CFDirectoriesSelectInput
type="host"
formik={formik}
index={index}
labelName="Host Directory:"
labelInfoTip="Select a directory on your host machine to share with the environment."
classNameContainer="w-full"
inputError={
// @ts-ignore
formik.errors.hostDirectories?.[index]?.hostDirectory
}
inputTouched={true}
/>
<CFDirectoriesSelectInput
type="mount"
formik={formik}
index={index}
labelName="Mount Path:"
labelInfoTip="Select a directory on your host machine to share with the environment."
classNameContainer="w-full"
rightTip
inputError={
// @ts-ignore
formik.errors.hostDirectories?.[index]?.mountPath
}
inputTouched={true}
/>
<div className="flex items-center justify-center pt-3 text-sm text-light-800">
<CFDellButton
disabled={disabled}
onClick={() => {
const hostDirectories = [...formik.values.hostDirectories];
hostDirectories.splice(index, 1);
formik.setFieldValue("hostDirectories", hostDirectories);
}}
/>
</div>
</div>
);
}
4 changes: 2 additions & 2 deletions src/components/FormInputText/FormInputText.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ReactElement } from "react";
import { ReactElement } from "react";
import InfoTip from "../InfoTip/InfoTip";
import InputText from "../InputText/InputText";
import InputError from "../InputError/InputError";
Expand Down Expand Up @@ -35,7 +35,7 @@ export default function FormInputText({
return (
<div data-tut={dataTut} className={classNameContainer}>
<div
className={`text-light-700 flex min-w-fit gap-1 pb-3 text-xs font-medium ${classNameInput}`}
className={`flex min-w-fit gap-1 pb-3 text-xs font-medium text-light-700 ${classNameInput}`}
>
{labelName}
<InfoTip content={labelInfoTip} rightTip={rightTip} />
Expand Down
Loading

0 comments on commit 1028c6b

Please sign in to comment.