forked from github/plane
chore: edit/delete option
This commit is contained in:
parent
cd4d56d071
commit
3c3f0f7581
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
@ -13,13 +13,20 @@ import { PrimaryButton } from "components/ui";
|
|||||||
import { ICustomAttribute } from "types";
|
import { ICustomAttribute } from "types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
data: ICustomAttribute | null;
|
||||||
objectId: string;
|
objectId: string;
|
||||||
|
onSubmit?: () => void;
|
||||||
parentId: string;
|
parentId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const OptionForm: React.FC<Props> = observer(({ objectId, parentId }) => {
|
export const OptionForm: React.FC<Props> = observer((props) => {
|
||||||
const [optionName, setOptionName] = useState("");
|
const { data, objectId, onSubmit, parentId } = props;
|
||||||
const [optionColor, setOptionColor] = useState("#000000");
|
|
||||||
|
const [option, setOption] = useState<Partial<ICustomAttribute>>({
|
||||||
|
display_name: "",
|
||||||
|
color: "#000000",
|
||||||
|
});
|
||||||
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
@ -29,47 +36,90 @@ export const OptionForm: React.FC<Props> = observer(({ objectId, parentId }) =>
|
|||||||
const handleCreateOption = async () => {
|
const handleCreateOption = async () => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
|
|
||||||
if (!optionName || optionName === "") return;
|
if (option.display_name === "") return;
|
||||||
|
|
||||||
const payload: Partial<ICustomAttribute> = {
|
const payload: Partial<ICustomAttribute> = {
|
||||||
color: optionColor,
|
color: option.color,
|
||||||
display_name: optionName,
|
display_name: option.display_name,
|
||||||
type: "option",
|
type: "option",
|
||||||
};
|
};
|
||||||
|
|
||||||
await customAttributes
|
await customAttributes.createAttributeOption(workspaceSlug.toString(), objectId, {
|
||||||
.createAttributeOption(workspaceSlug.toString(), objectId, {
|
...payload,
|
||||||
...payload,
|
parent: parentId,
|
||||||
parent: parentId,
|
});
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
setOptionName("");
|
|
||||||
setOptionColor("#000000");
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleUpdateOption = async () => {
|
||||||
|
if (!workspaceSlug) return;
|
||||||
|
|
||||||
|
if (option.display_name === "" || !option.parent || !option.id) return;
|
||||||
|
|
||||||
|
setIsEditing(true);
|
||||||
|
|
||||||
|
const payload: Partial<ICustomAttribute> = {
|
||||||
|
color: option.color,
|
||||||
|
display_name: option.display_name,
|
||||||
|
};
|
||||||
|
|
||||||
|
await customAttributes
|
||||||
|
.updateAttributeOption(workspaceSlug.toString(), objectId, option.parent, option.id, payload)
|
||||||
|
.finally(() => setIsEditing(false));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFormSubmit = async () => {
|
||||||
|
if (data) await handleUpdateOption();
|
||||||
|
else await handleCreateOption();
|
||||||
|
|
||||||
|
setOption({
|
||||||
|
display_name: "",
|
||||||
|
color: "#000000",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (onSubmit) onSubmit();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
setOption({ ...data });
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="bg-custom-background-100 rounded border border-custom-border-200 flex items-center gap-2 px-3 py-2 flex-grow">
|
<div className="bg-custom-background-100 rounded border border-custom-border-200 flex items-center gap-2 px-3 py-2 flex-grow">
|
||||||
{/* <span className="flex-shrink-0 text-xs grid place-items-center">🚀</span> */}
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="flex-grow border-none outline-none placeholder:text-custom-text-400 text-xs"
|
className="flex-grow border-none outline-none placeholder:text-custom-text-400 text-xs"
|
||||||
value={optionName}
|
value={option.display_name}
|
||||||
onChange={(e) => setOptionName(e.target.value)}
|
onChange={(e) => setOption((prev) => ({ ...prev, display_name: e.target.value }))}
|
||||||
placeholder="Enter new option"
|
placeholder="Enter new option"
|
||||||
/>
|
/>
|
||||||
<ColorPicker onChange={(val) => setOptionColor(val)} selectedColor={optionColor} />
|
<ColorPicker
|
||||||
|
onChange={(val) => setOption((prev) => ({ ...prev, color: val }))}
|
||||||
|
selectedColor={option.color ?? "#000000"}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<PrimaryButton
|
{data ? (
|
||||||
onClick={handleCreateOption}
|
<PrimaryButton
|
||||||
size="sm"
|
onClick={handleFormSubmit}
|
||||||
className="!py-1.5 !px-2"
|
size="sm"
|
||||||
loading={customAttributes.createAttributeOptionLoader}
|
className="!py-1.5 !px-2"
|
||||||
>
|
loading={isEditing}
|
||||||
{customAttributes.createAttributeOptionLoader ? "Adding..." : "Add"}
|
>
|
||||||
</PrimaryButton>
|
{isEditing ? "Updating..." : "Update"}
|
||||||
|
</PrimaryButton>
|
||||||
|
) : (
|
||||||
|
<PrimaryButton
|
||||||
|
onClick={handleFormSubmit}
|
||||||
|
size="sm"
|
||||||
|
className="!py-1.5 !px-2"
|
||||||
|
loading={customAttributes.createAttributeOptionLoader}
|
||||||
|
>
|
||||||
|
{customAttributes.createAttributeOptionLoader ? "Adding..." : "Add"}
|
||||||
|
</PrimaryButton>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
|
|
||||||
// mobx
|
// mobx
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
@ -7,9 +7,13 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
|||||||
import { Controller } from "react-hook-form";
|
import { Controller } from "react-hook-form";
|
||||||
// components
|
// components
|
||||||
import { FormComponentProps, Input, OptionForm, SelectOption } from "components/custom-attributes";
|
import { FormComponentProps, Input, OptionForm, SelectOption } from "components/custom-attributes";
|
||||||
|
// types
|
||||||
|
import { ICustomAttribute } from "types";
|
||||||
|
|
||||||
export const SelectAttributeForm: React.FC<FormComponentProps & { multiple?: boolean }> = observer(
|
export const SelectAttributeForm: React.FC<FormComponentProps & { multiple?: boolean }> = observer(
|
||||||
({ control, multiple = false, objectId = "", watch }) => {
|
({ control, multiple = false, objectId = "", watch }) => {
|
||||||
|
const [optionToEdit, setOptionToEdit] = useState<ICustomAttribute | null>(null);
|
||||||
|
|
||||||
const { customAttributes: customAttributesStore } = useMobxStore();
|
const { customAttributes: customAttributesStore } = useMobxStore();
|
||||||
const { entityAttributes } = customAttributesStore;
|
const { entityAttributes } = customAttributesStore;
|
||||||
|
|
||||||
@ -28,11 +32,21 @@ export const SelectAttributeForm: React.FC<FormComponentProps & { multiple?: boo
|
|||||||
<p className="text-xs">Options</p>
|
<p className="text-xs">Options</p>
|
||||||
<div className="mt-3 space-y-2 w-3/5">
|
<div className="mt-3 space-y-2 w-3/5">
|
||||||
{options?.map((option) => (
|
{options?.map((option) => (
|
||||||
<SelectOption key={option.id} objectId={objectId} option={option} />
|
<SelectOption
|
||||||
|
key={option.id}
|
||||||
|
handleEditOption={() => setOptionToEdit(option)}
|
||||||
|
objectId={objectId}
|
||||||
|
option={option}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 w-3/5">
|
<div className="mt-2 w-3/5">
|
||||||
<OptionForm objectId={objectId} parentId={watch("id") ?? ""} />
|
<OptionForm
|
||||||
|
data={optionToEdit}
|
||||||
|
objectId={objectId}
|
||||||
|
onSubmit={() => setOptionToEdit(null)}
|
||||||
|
parentId={watch("id") ?? ""}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,11 +11,14 @@ import { MoreHorizontal } from "lucide-react";
|
|||||||
import { ICustomAttribute } from "types";
|
import { ICustomAttribute } from "types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
handleEditOption: () => void;
|
||||||
objectId: string;
|
objectId: string;
|
||||||
option: ICustomAttribute;
|
option: ICustomAttribute;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SelectOption: React.FC<Props> = observer(({ objectId, option }) => {
|
export const SelectOption: React.FC<Props> = observer((props) => {
|
||||||
|
const { handleEditOption, objectId, option } = props;
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
@ -82,7 +85,7 @@ export const SelectOption: React.FC<Props> = observer(({ objectId, option }) =>
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<CustomMenu.MenuItem>Edit</CustomMenu.MenuItem>
|
<CustomMenu.MenuItem onClick={handleEditOption}>Edit</CustomMenu.MenuItem>
|
||||||
<CustomMenu.MenuItem onClick={handleDeleteOption}>Delete</CustomMenu.MenuItem>
|
<CustomMenu.MenuItem onClick={handleDeleteOption}>Delete</CustomMenu.MenuItem>
|
||||||
</CustomMenu>
|
</CustomMenu>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user