mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: estimate dropdown handled in issues
This commit is contained in:
parent
78db7fe03f
commit
2adb18f636
2
packages/types/src/issues/issue.d.ts
vendored
2
packages/types/src/issues/issue.d.ts
vendored
@ -15,7 +15,7 @@ export type TIssue = {
|
|||||||
priority: TIssuePriorities;
|
priority: TIssuePriorities;
|
||||||
label_ids: string[];
|
label_ids: string[];
|
||||||
assignee_ids: string[];
|
assignee_ids: string[];
|
||||||
estimate_point: number | null;
|
estimate_point: string | null;
|
||||||
|
|
||||||
sub_issues_count: number;
|
sub_issues_count: number;
|
||||||
attachment_count: number;
|
attachment_count: number;
|
||||||
|
@ -5,7 +5,7 @@ import { Controller, useForm } from "react-hook-form"; // services
|
|||||||
import { usePopper } from "react-popper";
|
import { usePopper } from "react-popper";
|
||||||
// ui
|
// ui
|
||||||
import { AlertCircle } from "lucide-react";
|
import { AlertCircle } from "lucide-react";
|
||||||
import { Popover, PopoverButton, PopoverPanel, Transition } from "@headlessui/react";
|
import { Popover, Transition } from "@headlessui/react";
|
||||||
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
import { RichTextReadOnlyEditor } from "@/components/editor/rich-text-editor/rich-text-read-only-editor";
|
import { RichTextReadOnlyEditor } from "@/components/editor/rich-text-editor/rich-text-read-only-editor";
|
||||||
// icons
|
// icons
|
||||||
@ -178,9 +178,9 @@ export const GptAssistantPopover: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover as="div" className={`relative w-min text-left`}>
|
<Popover as="div" className={`relative w-min text-left`}>
|
||||||
<PopoverButton as={Fragment}>
|
<Popover.Button as={Fragment}>
|
||||||
<button ref={setReferenceElement}>{button}</button>
|
<button ref={setReferenceElement}>{button}</button>
|
||||||
</PopoverButton>
|
</Popover.Button>
|
||||||
<Transition
|
<Transition
|
||||||
show={isOpen}
|
show={isOpen}
|
||||||
as={React.Fragment}
|
as={React.Fragment}
|
||||||
@ -191,7 +191,7 @@ export const GptAssistantPopover: React.FC<Props> = (props) => {
|
|||||||
leaveFrom="transform opacity-100 scale-100"
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
leaveTo="transform opacity-0 scale-95"
|
leaveTo="transform opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<PopoverPanel
|
<Popover.Panel
|
||||||
as="div"
|
as="div"
|
||||||
className={`fixed z-10 flex w-full min-w-[50rem] max-w-full flex-col space-y-4 overflow-hidden rounded-[10px] border border-custom-border-200 bg-custom-background-100 p-4 shadow ${className}`}
|
className={`fixed z-10 flex w-full min-w-[50rem] max-w-full flex-col space-y-4 overflow-hidden rounded-[10px] border border-custom-border-200 bg-custom-background-100 p-4 shadow ${className}`}
|
||||||
ref={setPopperElement as Ref<HTMLDivElement>}
|
ref={setPopperElement as Ref<HTMLDivElement>}
|
||||||
@ -261,7 +261,7 @@ export const GptAssistantPopover: React.FC<Props> = (props) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PopoverPanel>
|
</Popover.Panel>
|
||||||
</Transition>
|
</Transition>
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Fragment, ReactNode, useRef, useState } from "react";
|
import { Fragment, ReactNode, useRef, useState } from "react";
|
||||||
import sortBy from "lodash/sortBy";
|
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { usePopper } from "react-popper";
|
import { usePopper } from "react-popper";
|
||||||
import { Check, ChevronDown, Search, Triangle } from "lucide-react";
|
import { Check, ChevronDown, Search, Triangle } from "lucide-react";
|
||||||
@ -9,6 +8,8 @@ import { cn } from "@/helpers/common.helper";
|
|||||||
// hooks
|
// hooks
|
||||||
import {
|
import {
|
||||||
useAppRouter,
|
useAppRouter,
|
||||||
|
useEstimate,
|
||||||
|
useProjectEstimates,
|
||||||
// useEstimate
|
// useEstimate
|
||||||
} from "@/hooks/store";
|
} from "@/hooks/store";
|
||||||
import { useDropdown } from "@/hooks/use-dropdown";
|
import { useDropdown } from "@/hooks/use-dropdown";
|
||||||
@ -22,15 +23,15 @@ type Props = TDropdownProps & {
|
|||||||
button?: ReactNode;
|
button?: ReactNode;
|
||||||
dropdownArrow?: boolean;
|
dropdownArrow?: boolean;
|
||||||
dropdownArrowClassName?: string;
|
dropdownArrowClassName?: string;
|
||||||
onChange: (val: number | null) => void;
|
onChange: (val: string | undefined) => void;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
value: number | null;
|
value: string | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DropdownOptions =
|
type DropdownOptions =
|
||||||
| {
|
| {
|
||||||
value: number | null;
|
value: string | null;
|
||||||
query: string;
|
query: string;
|
||||||
content: JSX.Element;
|
content: JSX.Element;
|
||||||
}[]
|
}[]
|
||||||
@ -79,23 +80,29 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||||||
});
|
});
|
||||||
// store hooks
|
// store hooks
|
||||||
const { workspaceSlug } = useAppRouter();
|
const { workspaceSlug } = useAppRouter();
|
||||||
console.log("workspaceSlug", workspaceSlug);
|
|
||||||
console.log("projectId", projectId);
|
|
||||||
|
|
||||||
// const { fetchProjectEstimates, getProjectActiveEstimateDetails, getEstimatePointValue } = useEstimate();
|
const { currentActiveEstimateId, getProjectEstimates } = useProjectEstimates();
|
||||||
// const activeEstimate = getProjectActiveEstimateDetails(projectId);
|
const { estimatePointIds, estimatePointById } = useEstimate(
|
||||||
const activeEstimate: any = undefined;
|
currentActiveEstimateId ? currentActiveEstimateId : undefined
|
||||||
|
);
|
||||||
|
|
||||||
const options: DropdownOptions = sortBy(activeEstimate?.points ?? [], "key")?.map((point) => ({
|
const options: DropdownOptions = (estimatePointIds ?? [])
|
||||||
value: point.key,
|
?.map((estimatePoint) => {
|
||||||
query: `${point?.value}`,
|
const currentEstimatePoint = estimatePointById(estimatePoint);
|
||||||
|
if (currentEstimatePoint)
|
||||||
|
return {
|
||||||
|
value: currentEstimatePoint.id,
|
||||||
|
query: `${currentEstimatePoint?.value}`,
|
||||||
content: (
|
content: (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Triangle className="h-3 w-3 flex-shrink-0" />
|
<Triangle className="h-3 w-3 flex-shrink-0" />
|
||||||
<span className="flex-grow truncate">{point.value}</span>
|
<span className="flex-grow truncate">{currentEstimatePoint.value}</span>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
}));
|
};
|
||||||
|
else undefined;
|
||||||
|
})
|
||||||
|
.filter((estimatePointDropdownOption) => estimatePointDropdownOption != undefined) as DropdownOptions;
|
||||||
options?.unshift({
|
options?.unshift({
|
||||||
value: null,
|
value: null,
|
||||||
query: "No estimate",
|
query: "No estimate",
|
||||||
@ -110,14 +117,10 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||||||
const filteredOptions =
|
const filteredOptions =
|
||||||
query === "" ? options : options?.filter((o) => o.query.toLowerCase().includes(query.toLowerCase()));
|
query === "" ? options : options?.filter((o) => o.query.toLowerCase().includes(query.toLowerCase()));
|
||||||
|
|
||||||
const selectedEstimate =
|
const selectedEstimate = value && estimatePointById ? estimatePointById(value) : undefined;
|
||||||
value !== null
|
|
||||||
? // getEstimatePointValue(value, projectId)
|
|
||||||
null
|
|
||||||
: null;
|
|
||||||
|
|
||||||
const onOpen = async () => {
|
const onOpen = async () => {
|
||||||
// if (!activeEstimate && workspaceSlug) await fetchProjectEstimates(workspaceSlug, projectId);
|
if (!currentActiveEstimateId && workspaceSlug) await getProjectEstimates(workspaceSlug, projectId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const { handleClose, handleKeyDown, handleOnClick, searchInputKeyDown } = useDropdown({
|
const { handleClose, handleKeyDown, handleOnClick, searchInputKeyDown } = useDropdown({
|
||||||
@ -131,7 +134,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||||||
setQuery,
|
setQuery,
|
||||||
});
|
});
|
||||||
|
|
||||||
const dropdownOnChange = (val: number | null) => {
|
const dropdownOnChange = (val: string | undefined) => {
|
||||||
onChange(val);
|
onChange(val);
|
||||||
handleClose();
|
handleClose();
|
||||||
};
|
};
|
||||||
@ -175,13 +178,13 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||||||
className={buttonClassName}
|
className={buttonClassName}
|
||||||
isActive={isOpen}
|
isActive={isOpen}
|
||||||
tooltipHeading="Estimate"
|
tooltipHeading="Estimate"
|
||||||
tooltipContent={selectedEstimate !== null ? selectedEstimate : placeholder}
|
tooltipContent={selectedEstimate ? selectedEstimate?.value : placeholder}
|
||||||
showTooltip={showTooltip}
|
showTooltip={showTooltip}
|
||||||
variant={buttonVariant}
|
variant={buttonVariant}
|
||||||
>
|
>
|
||||||
{!hideIcon && <Triangle className="h-3 w-3 flex-shrink-0" />}
|
{!hideIcon && <Triangle className="h-3 w-3 flex-shrink-0" />}
|
||||||
{(selectedEstimate || placeholder) && BUTTON_VARIANTS_WITH_TEXT.includes(buttonVariant) && (
|
{(selectedEstimate || placeholder) && BUTTON_VARIANTS_WITH_TEXT.includes(buttonVariant) && (
|
||||||
<span className="flex-grow truncate">{selectedEstimate !== null ? selectedEstimate : placeholder}</span>
|
<span className="flex-grow truncate">{selectedEstimate ? selectedEstimate?.value : placeholder}</span>
|
||||||
)}
|
)}
|
||||||
{dropdownArrow && (
|
{dropdownArrow && (
|
||||||
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
<ChevronDown className={cn("h-2.5 w-2.5 flex-shrink-0", dropdownArrowClassName)} aria-hidden="true" />
|
||||||
@ -215,20 +218,14 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
|
|||||||
{filteredOptions ? (
|
{filteredOptions ? (
|
||||||
filteredOptions.length > 0 ? (
|
filteredOptions.length > 0 ? (
|
||||||
filteredOptions.map((option) => (
|
filteredOptions.map((option) => (
|
||||||
<Combobox.Option
|
<Combobox.Option key={option.value} value={option.value}>
|
||||||
key={option.value}
|
{({ active, selected }) => (
|
||||||
value={option.value}
|
<div
|
||||||
className={({ active, selected }) =>
|
className={`flex w-full cursor-pointer select-none items-center justify-between gap-2 truncate rounded px-1 py-1.5 ${active ? `!hover:bg-custom-background-80` : ``} ${selected ? "text-custom-text-100" : "text-custom-text-200"}`}
|
||||||
`flex w-full cursor-pointer select-none items-center justify-between gap-2 truncate rounded px-1 py-1.5 ${
|
|
||||||
active ? "bg-custom-background-80" : ""
|
|
||||||
} ${selected ? "text-custom-text-100" : "text-custom-text-200"}`
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{({ selected }) => (
|
|
||||||
<>
|
|
||||||
<span className="flex-grow truncate">{option.content}</span>
|
<span className="flex-grow truncate">{option.content}</span>
|
||||||
{selected && <Check className="h-3.5 w-3.5 flex-shrink-0" />}
|
{selected && <Check className="h-3.5 w-3.5 flex-shrink-0" />}
|
||||||
</>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Combobox.Option>
|
</Combobox.Option>
|
||||||
))
|
))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Ref, useState } from "react";
|
import { Ref, useState } from "react";
|
||||||
import { usePopper } from "react-popper";
|
import { usePopper } from "react-popper";
|
||||||
import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react";
|
import { Popover } from "@headlessui/react";
|
||||||
// popper
|
// popper
|
||||||
// helper
|
// helper
|
||||||
import { getButtonStyling } from "@plane/ui";
|
import { getButtonStyling } from "@plane/ui";
|
||||||
@ -42,7 +42,7 @@ export const ComicBoxButton: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverButton ref={setReferenceElement} onClick={onClick} disabled={disabled}>
|
<Popover.Button ref={setReferenceElement} onClick={onClick} disabled={disabled}>
|
||||||
<div className={`flex items-center gap-2.5 ${getButtonStyling("primary", "lg", disabled)}`}>
|
<div className={`flex items-center gap-2.5 ${getButtonStyling("primary", "lg", disabled)}`}>
|
||||||
{icon}
|
{icon}
|
||||||
<span className="leading-4">{label}</span>
|
<span className="leading-4">{label}</span>
|
||||||
@ -55,9 +55,9 @@ export const ComicBoxButton: React.FC<Props> = (props) => {
|
|||||||
<div className={`absolute bg-blue-400/40 right-0 h-1.5 w-1.5 mt-0.5 mr-0.5 rounded-full`} />
|
<div className={`absolute bg-blue-400/40 right-0 h-1.5 w-1.5 mt-0.5 mr-0.5 rounded-full`} />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</PopoverButton>
|
</Popover.Button>
|
||||||
{isHovered && (
|
{isHovered && (
|
||||||
<PopoverPanel
|
<Popover.Panel
|
||||||
as="div"
|
as="div"
|
||||||
className="flex flex-col rounded border border-custom-border-200 bg-custom-background-100 p-5 relative min-w-80"
|
className="flex flex-col rounded border border-custom-border-200 bg-custom-background-100 p-5 relative min-w-80"
|
||||||
ref={setPopperElement as Ref<HTMLDivElement>}
|
ref={setPopperElement as Ref<HTMLDivElement>}
|
||||||
@ -68,7 +68,7 @@ export const ComicBoxButton: React.FC<Props> = (props) => {
|
|||||||
<div className="absolute w-2 h-2 bg-custom-background-100 border rounded-lb-sm border-custom-border-200 border-r-0 border-t-0 transform rotate-45 bottom-2 -left-[5px]" />
|
<div className="absolute w-2 h-2 bg-custom-background-100 border rounded-lb-sm border-custom-border-200 border-r-0 border-t-0 transform rotate-45 bottom-2 -left-[5px]" />
|
||||||
<h3 className="text-lg font-semibold w-full">{title}</h3>
|
<h3 className="text-lg font-semibold w-full">{title}</h3>
|
||||||
<h4 className="mt-1 text-sm">{description}</h4>
|
<h4 className="mt-1 text-sm">{description}</h4>
|
||||||
</PopoverPanel>
|
</Popover.Panel>
|
||||||
)}
|
)}
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { FC, useRef, Fragment, useState } from "react";
|
import { FC, useRef, Fragment, useState } from "react";
|
||||||
import { Info, Check, ChevronDown } from "lucide-react";
|
import { Info, Check, ChevronDown } from "lucide-react";
|
||||||
import { Listbox, ListboxButton, ListboxOptions, Transition, ListboxOption } from "@headlessui/react";
|
import { Listbox, Transition } from "@headlessui/react";
|
||||||
import { TEstimatePointsObject } from "@plane/types";
|
import { TEstimatePointsObject } from "@plane/types";
|
||||||
import { Tooltip } from "@plane/ui";
|
import { Tooltip } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
@ -51,7 +51,7 @@ export const EstimatePointDropdown: FC<TEstimatePointDropdown> = (props) => {
|
|||||||
}}
|
}}
|
||||||
className="w-full flex-shrink-0 text-left"
|
className="w-full flex-shrink-0 text-left"
|
||||||
>
|
>
|
||||||
<ListboxButton
|
<Listbox.Button
|
||||||
type="button"
|
type="button"
|
||||||
ref={buttonRef}
|
ref={buttonRef}
|
||||||
onClick={() => setIsDropdownOpen((prev) => !prev)}
|
onClick={() => setIsDropdownOpen((prev) => !prev)}
|
||||||
@ -75,7 +75,7 @@ export const EstimatePointDropdown: FC<TEstimatePointDropdown> = (props) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</ListboxButton>
|
</Listbox.Button>
|
||||||
<Transition
|
<Transition
|
||||||
show={isDropdownOpen}
|
show={isDropdownOpen}
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
@ -86,12 +86,12 @@ export const EstimatePointDropdown: FC<TEstimatePointDropdown> = (props) => {
|
|||||||
leaveFrom="transform opacity-100 scale-100"
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
leaveTo="transform opacity-0 scale-95"
|
leaveTo="transform opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<ListboxOptions
|
<Listbox.Options
|
||||||
ref={dropdownRef}
|
ref={dropdownRef}
|
||||||
className="fixed z-10 mt-1 h-fit w-48 sm:w-60 overflow-y-auto rounded-md border border-custom-border-200 bg-custom-background-100 shadow-sm focus:outline-none"
|
className="fixed z-10 mt-1 h-fit w-48 sm:w-60 overflow-y-auto rounded-md border border-custom-border-200 bg-custom-background-100 shadow-sm focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="p-1.5">
|
<div className="p-1.5">
|
||||||
<ListboxOption
|
<Listbox.Option
|
||||||
value={"none"}
|
value={"none"}
|
||||||
className={cn(
|
className={cn(
|
||||||
`cursor-pointer select-none truncate rounded px-1 py-1.5 hover:bg-custom-background-90`,
|
`cursor-pointer select-none truncate rounded px-1 py-1.5 hover:bg-custom-background-90`,
|
||||||
@ -102,9 +102,9 @@ export const EstimatePointDropdown: FC<TEstimatePointDropdown> = (props) => {
|
|||||||
<div className="text-sm font-medium w-full line-clamp-1">None</div>
|
<div className="text-sm font-medium w-full line-clamp-1">None</div>
|
||||||
{selectedOption === "none" && <Check size={12} />}
|
{selectedOption === "none" && <Check size={12} />}
|
||||||
</div>
|
</div>
|
||||||
</ListboxOption>
|
</Listbox.Option>
|
||||||
{options.map((option) => (
|
{options.map((option) => (
|
||||||
<ListboxOption
|
<Listbox.Option
|
||||||
key={option?.key}
|
key={option?.key}
|
||||||
value={option?.id}
|
value={option?.id}
|
||||||
className={cn(
|
className={cn(
|
||||||
@ -116,10 +116,10 @@ export const EstimatePointDropdown: FC<TEstimatePointDropdown> = (props) => {
|
|||||||
<div className="text-sm font-medium w-full line-clamp-1">{option.value}</div>
|
<div className="text-sm font-medium w-full line-clamp-1">{option.value}</div>
|
||||||
{selectedOption === option?.id && <Check size={12} />}
|
{selectedOption === option?.id && <Check size={12} />}
|
||||||
</div>
|
</div>
|
||||||
</ListboxOption>
|
</Listbox.Option>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</ListboxOptions>
|
</Listbox.Options>
|
||||||
</Transition>
|
</Transition>
|
||||||
</Listbox>
|
</Listbox>
|
||||||
</div>
|
</div>
|
||||||
|
@ -69,7 +69,7 @@ export const EstimatePointUpdate: FC<TEstimatePointUpdate> = observer((props) =>
|
|||||||
let isEstimateValid = false;
|
let isEstimateValid = false;
|
||||||
|
|
||||||
const currentEstimatePointValues = estimatePoints
|
const currentEstimatePointValues = estimatePoints
|
||||||
.map((point) => point?.value || undefined)
|
.map((point) => (point?.id != estimatePoint?.id ? point?.value : undefined))
|
||||||
.filter((value) => value != undefined) as string[];
|
.filter((value) => value != undefined) as string[];
|
||||||
const isRepeated =
|
const isRepeated =
|
||||||
(estimateType && isEstimatePointValuesRepeated(currentEstimatePointValues, estimateType, estimateInputValue)) ||
|
(estimateType && isEstimatePointValuesRepeated(currentEstimatePointValues, estimateType, estimateInputValue)) ||
|
||||||
|
@ -142,10 +142,10 @@ export const InboxIssueProperties: FC<TInboxIssueProperties> = observer((props)
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* estimate */}
|
{/* estimate */}
|
||||||
{isVisible && areEstimateEnabledByProjectId(projectId) && (
|
{isVisible && projectId && areEstimateEnabledByProjectId(projectId) && (
|
||||||
<div className="h-7">
|
<div className="h-7">
|
||||||
<EstimateDropdown
|
<EstimateDropdown
|
||||||
value={data?.estimate_point || null}
|
value={data?.estimate_point || undefined}
|
||||||
onChange={(estimatePoint) => handleData("estimate_point", estimatePoint)}
|
onChange={(estimatePoint) => handleData("estimate_point", estimatePoint)}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
buttonVariant="border-with-text"
|
buttonVariant="border-with-text"
|
||||||
|
@ -54,13 +54,7 @@ import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper"
|
|||||||
import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper";
|
import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper";
|
||||||
import { copyTextToClipboard } from "@/helpers/string.helper";
|
import { copyTextToClipboard } from "@/helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import {
|
import { useProjectEstimates, useIssueDetail, useProject, useProjectState, useUser } from "@/hooks/store";
|
||||||
// useEstimate,
|
|
||||||
useIssueDetail,
|
|
||||||
useProject,
|
|
||||||
useProjectState,
|
|
||||||
useUser,
|
|
||||||
} from "@/hooks/store";
|
|
||||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||||
// components
|
// components
|
||||||
import type { TIssueOperations } from "./root";
|
import type { TIssueOperations } from "./root";
|
||||||
@ -88,8 +82,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
// store hooks
|
// store hooks
|
||||||
const { getProjectById } = useProject();
|
const { getProjectById } = useProject();
|
||||||
const { data: currentUser } = useUser();
|
const { data: currentUser } = useUser();
|
||||||
// const { areEstimatesEnabledForCurrentProject } = useEstimate();
|
const { areEstimateEnabledByProjectId } = useProjectEstimates();
|
||||||
const areEstimatesEnabledForCurrentProject = false;
|
|
||||||
const {
|
const {
|
||||||
issue: { getIssueById },
|
issue: { getIssueById },
|
||||||
} = useIssueDetail();
|
} = useIssueDetail();
|
||||||
@ -319,15 +312,17 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{areEstimatesEnabledForCurrentProject && (
|
{projectId && areEstimateEnabledByProjectId(projectId) && (
|
||||||
<div className="flex h-8 items-center gap-2">
|
<div className="flex h-8 items-center gap-2">
|
||||||
<div className="flex w-2/5 flex-shrink-0 items-center gap-1 text-sm text-custom-text-300">
|
<div className="flex w-2/5 flex-shrink-0 items-center gap-1 text-sm text-custom-text-300">
|
||||||
<Triangle className="h-4 w-4 flex-shrink-0" />
|
<Triangle className="h-4 w-4 flex-shrink-0" />
|
||||||
<span>Estimate</span>
|
<span>Estimate</span>
|
||||||
</div>
|
</div>
|
||||||
<EstimateDropdown
|
<EstimateDropdown
|
||||||
value={issue?.estimate_point !== null ? issue.estimate_point : null}
|
value={issue?.estimate_point ?? undefined}
|
||||||
onChange={(val) => issueOperations.update(workspaceSlug, projectId, issueId, { estimate_point: val })}
|
onChange={(val: string | undefined) =>
|
||||||
|
issueOperations.update(workspaceSlug, projectId, issueId, { estimate_point: val })
|
||||||
|
}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
disabled={!isEditable}
|
disabled={!isEditable}
|
||||||
buttonVariant="transparent-with-text"
|
buttonVariant="transparent-with-text"
|
||||||
|
@ -220,7 +220,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEstimate = (value: number | null) => {
|
const handleEstimate = (value: string | undefined) => {
|
||||||
updateIssue &&
|
updateIssue &&
|
||||||
updateIssue(issue.project_id, issue.id, { estimate_point: value }).then(() => {
|
updateIssue(issue.project_id, issue.id, { estimate_point: value }).then(() => {
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
@ -398,7 +398,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="estimate">
|
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="estimate">
|
||||||
<div className="h-5" onClick={handleEventPropagation}>
|
<div className="h-5" onClick={handleEventPropagation}>
|
||||||
<EstimateDropdown
|
<EstimateDropdown
|
||||||
value={issue.estimate_point}
|
value={issue.estimate_point ?? undefined}
|
||||||
onChange={handleEstimate}
|
onChange={handleEstimate}
|
||||||
projectId={issue.project_id}
|
projectId={issue.project_id}
|
||||||
disabled={isReadOnly}
|
disabled={isReadOnly}
|
||||||
|
@ -17,7 +17,7 @@ export const SpreadsheetEstimateColumn: React.FC<Props> = observer((props: Props
|
|||||||
return (
|
return (
|
||||||
<div className="h-11 border-b-[0.5px] border-custom-border-200">
|
<div className="h-11 border-b-[0.5px] border-custom-border-200">
|
||||||
<EstimateDropdown
|
<EstimateDropdown
|
||||||
value={issue.estimate_point}
|
value={issue.estimate_point || undefined}
|
||||||
onChange={(data) =>
|
onChange={(data) =>
|
||||||
onChange(issue, { estimate_point: data }, { changed_property: "estimate_point", change_details: data })
|
onChange(issue, { estimate_point: data }, { changed_property: "estimate_point", change_details: data })
|
||||||
}
|
}
|
||||||
|
@ -673,7 +673,7 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<div className="h-7">
|
<div className="h-7">
|
||||||
<EstimateDropdown
|
<EstimateDropdown
|
||||||
value={value}
|
value={value || undefined}
|
||||||
onChange={(estimatePoint) => {
|
onChange={(estimatePoint) => {
|
||||||
onChange(estimatePoint);
|
onChange(estimatePoint);
|
||||||
handleFormChange();
|
handleFormChange();
|
||||||
|
@ -197,14 +197,14 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
|||||||
<span>Estimate</span>
|
<span>Estimate</span>
|
||||||
</div>
|
</div>
|
||||||
<EstimateDropdown
|
<EstimateDropdown
|
||||||
value={issue?.estimate_point !== null ? issue.estimate_point : null}
|
value={issue.estimate_point ?? undefined}
|
||||||
onChange={(val) => issueOperations.update(workspaceSlug, projectId, issueId, { estimate_point: val })}
|
onChange={(val) => issueOperations.update(workspaceSlug, projectId, issueId, { estimate_point: val })}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
buttonVariant="transparent-with-text"
|
buttonVariant="transparent-with-text"
|
||||||
className="w-3/4 flex-grow group"
|
className="w-3/4 flex-grow group"
|
||||||
buttonContainerClassName="w-full text-left"
|
buttonContainerClassName="w-full text-left"
|
||||||
buttonClassName={`text-sm ${issue?.estimate_point !== null ? "" : "text-custom-text-400"}`}
|
buttonClassName={`text-sm ${issue?.estimate_point !== undefined ? "" : "text-custom-text-400"}`}
|
||||||
placeholder="None"
|
placeholder="None"
|
||||||
hideIcon
|
hideIcon
|
||||||
dropdownArrow
|
dropdownArrow
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { Field, Label, Radio, RadioGroup } from "@headlessui/react";
|
|
||||||
// helpers
|
|
||||||
import { cn } from "@/helpers/common.helper";
|
|
||||||
|
|
||||||
type RadioInputProps = {
|
|
||||||
label: string | React.ReactNode | undefined;
|
|
||||||
labelClassName?: string;
|
|
||||||
ariaLabel?: string;
|
|
||||||
options: { label: string; value: string; disabled?: boolean }[];
|
|
||||||
vertical?: boolean;
|
|
||||||
selected: string;
|
|
||||||
onChange: (value: string) => void;
|
|
||||||
className?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const RadioInput = ({
|
|
||||||
label: inputLabel,
|
|
||||||
labelClassName: inputLabelClassName,
|
|
||||||
options,
|
|
||||||
vertical,
|
|
||||||
selected,
|
|
||||||
ariaLabel,
|
|
||||||
onChange,
|
|
||||||
className,
|
|
||||||
}: RadioInputProps) => {
|
|
||||||
const wrapperClass = vertical ? "flex flex-col gap-1" : "flex gap-2";
|
|
||||||
|
|
||||||
const setSelected = (value: string) => {
|
|
||||||
onChange(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
let aria = ariaLabel ? ariaLabel.toLowerCase().replace(" ", "-") : "";
|
|
||||||
if (!aria && typeof inputLabel === "string") {
|
|
||||||
aria = inputLabel.toLowerCase().replace(" ", "-");
|
|
||||||
} else {
|
|
||||||
aria = "radio-input";
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RadioGroup value={selected} onChange={setSelected} aria-label={aria} className={className}>
|
|
||||||
<Label className={cn(`mb-2`, inputLabelClassName)}>{inputLabel}</Label>
|
|
||||||
<div className={`${wrapperClass}`}>
|
|
||||||
{options.map(({ value, label, disabled }) => (
|
|
||||||
<Field key={label} className="flex items-center gap-2">
|
|
||||||
<Radio
|
|
||||||
value={value}
|
|
||||||
className="group flex size-5 items-center justify-center rounded-full border border-custom-border-400 bg-custom-background-500 data-[checked]:bg-custom-primary-200 data-[checked]:border-custom-primary-100 cursor-pointer
|
|
||||||
data-[disabled]:bg-custom-background-200
|
|
||||||
data-[disabled]:border-custom-border-200
|
|
||||||
data-[disabled]:cursor-not-allowed"
|
|
||||||
disabled={disabled}
|
|
||||||
>
|
|
||||||
<span className="invisible size-2 rounded-full bg-white group-data-[checked]:visible" />
|
|
||||||
</Radio>
|
|
||||||
<Label className="text-base cursor-pointer">{label}</Label>
|
|
||||||
</Field>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</RadioGroup>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { RadioInput };
|
|
@ -6,7 +6,7 @@ import { usePopper } from "react-popper";
|
|||||||
// icons
|
// icons
|
||||||
import { Activity, Check, ChevronDown, LogOut, Mails, PlusSquare, Settings } from "lucide-react";
|
import { Activity, Check, ChevronDown, LogOut, Mails, PlusSquare, Settings } from "lucide-react";
|
||||||
// ui
|
// ui
|
||||||
import { Menu, MenuButton, MenuItem, MenuItems, Transition } from "@headlessui/react";
|
import { Menu, Transition } from "@headlessui/react";
|
||||||
// types
|
// types
|
||||||
import { IWorkspace } from "@plane/types";
|
import { IWorkspace } from "@plane/types";
|
||||||
// plane ui
|
// plane ui
|
||||||
@ -104,7 +104,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
<Menu as="div" className="relative h-full flex-grow truncate text-left">
|
<Menu as="div" className="relative h-full flex-grow truncate text-left">
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<>
|
<>
|
||||||
<MenuButton className="group/menu-button h-full w-full truncate rounded-md text-sm font-medium text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:outline-none">
|
<Menu.Button className="group/menu-button h-full w-full truncate rounded-md text-sm font-medium text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:outline-none">
|
||||||
<div
|
<div
|
||||||
className={`flex items-center gap-x-2 truncate rounded p-1 ${
|
className={`flex items-center gap-x-2 truncate rounded p-1 ${
|
||||||
sidebarCollapsed ? "justify-center" : "justify-between"
|
sidebarCollapsed ? "justify-center" : "justify-between"
|
||||||
@ -126,7 +126,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</MenuButton>
|
</Menu.Button>
|
||||||
<Transition
|
<Transition
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="transition ease-out duration-100"
|
enter="transition ease-out duration-100"
|
||||||
@ -136,7 +136,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
leaveFrom="transform opacity-100 scale-100"
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
leaveTo="transform opacity-0 scale-95"
|
leaveTo="transform opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<MenuItems as={Fragment}>
|
<Menu.Items as={Fragment}>
|
||||||
<div className="fixed left-4 z-20 mt-1 flex w-full max-w-[19rem] origin-top-left flex-col divide-y divide-custom-border-100 rounded-md border-[0.5px] border-custom-sidebar-border-300 bg-custom-sidebar-background-100 shadow-custom-shadow-rg outline-none">
|
<div className="fixed left-4 z-20 mt-1 flex w-full max-w-[19rem] origin-top-left flex-col divide-y divide-custom-border-100 rounded-md border-[0.5px] border-custom-sidebar-border-300 bg-custom-sidebar-background-100 shadow-custom-shadow-rg outline-none">
|
||||||
<div className="vertical-scrollbar scrollbar-sm mb-2 flex max-h-96 flex-col items-start justify-start gap-2 overflow-y-scroll px-4">
|
<div className="vertical-scrollbar scrollbar-sm mb-2 flex max-h-96 flex-col items-start justify-start gap-2 overflow-y-scroll px-4">
|
||||||
<h6 className="sticky top-0 z-10 h-full w-full bg-custom-sidebar-background-100 pb-1 pt-3 text-sm font-medium text-custom-sidebar-text-400">
|
<h6 className="sticky top-0 z-10 h-full w-full bg-custom-sidebar-background-100 pb-1 pt-3 text-sm font-medium text-custom-sidebar-text-400">
|
||||||
@ -155,7 +155,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
}}
|
}}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
>
|
>
|
||||||
<MenuItem
|
<Menu.Item
|
||||||
as="div"
|
as="div"
|
||||||
className="flex items-center justify-between gap-1 rounded p-1 text-sm text-custom-sidebar-text-100 hover:bg-custom-sidebar-background-80"
|
className="flex items-center justify-between gap-1 rounded p-1 text-sm text-custom-sidebar-text-100 hover:bg-custom-sidebar-background-80"
|
||||||
>
|
>
|
||||||
@ -188,7 +188,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
<Check className="h-5 w-5 text-custom-sidebar-text-100" />
|
<Check className="h-5 w-5 text-custom-sidebar-text-100" />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</MenuItem>
|
</Menu.Item>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -203,13 +203,13 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex w-full flex-col items-start justify-start gap-2 px-4 py-2 text-sm">
|
<div className="flex w-full flex-col items-start justify-start gap-2 px-4 py-2 text-sm">
|
||||||
<Link href="/create-workspace" className="w-full">
|
<Link href="/create-workspace" className="w-full">
|
||||||
<MenuItem
|
<Menu.Item
|
||||||
as="div"
|
as="div"
|
||||||
className="flex items-center gap-2 rounded px-2 py-1 text-sm font-medium text-custom-sidebar-text-100 hover:bg-custom-sidebar-background-80"
|
className="flex items-center gap-2 rounded px-2 py-1 text-sm font-medium text-custom-sidebar-text-100 hover:bg-custom-sidebar-background-80"
|
||||||
>
|
>
|
||||||
<PlusSquare strokeWidth={1.75} className="h-4 w-4 flex-shrink-0" />
|
<PlusSquare strokeWidth={1.75} className="h-4 w-4 flex-shrink-0" />
|
||||||
Create workspace
|
Create workspace
|
||||||
</MenuItem>
|
</Menu.Item>
|
||||||
</Link>
|
</Link>
|
||||||
{userLinks(workspaceSlug?.toString() ?? "", currentUser?.id ?? "").map((link, index) => (
|
{userLinks(workspaceSlug?.toString() ?? "", currentUser?.id ?? "").map((link, index) => (
|
||||||
<Link
|
<Link
|
||||||
@ -220,18 +220,18 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
if (index > 0) handleItemClick();
|
if (index > 0) handleItemClick();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MenuItem
|
<Menu.Item
|
||||||
as="div"
|
as="div"
|
||||||
className="flex items-center gap-2 rounded px-2 py-1 text-sm font-medium text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80"
|
className="flex items-center gap-2 rounded px-2 py-1 text-sm font-medium text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80"
|
||||||
>
|
>
|
||||||
<link.icon className="h-4 w-4 flex-shrink-0" />
|
<link.icon className="h-4 w-4 flex-shrink-0" />
|
||||||
{link.name}
|
{link.name}
|
||||||
</MenuItem>
|
</Menu.Item>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full px-4 py-2">
|
<div className="w-full px-4 py-2">
|
||||||
<MenuItem
|
<Menu.Item
|
||||||
as="button"
|
as="button"
|
||||||
type="button"
|
type="button"
|
||||||
className="flex w-full items-center gap-2 rounded px-2 py-1 text-sm font-medium text-red-600 hover:bg-custom-sidebar-background-80"
|
className="flex w-full items-center gap-2 rounded px-2 py-1 text-sm font-medium text-red-600 hover:bg-custom-sidebar-background-80"
|
||||||
@ -239,17 +239,17 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
>
|
>
|
||||||
<LogOut className="h-4 w-4 flex-shrink-0" />
|
<LogOut className="h-4 w-4 flex-shrink-0" />
|
||||||
Sign out
|
Sign out
|
||||||
</MenuItem>
|
</Menu.Item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</MenuItems>
|
</Menu.Items>
|
||||||
</Transition>
|
</Transition>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Menu>
|
</Menu>
|
||||||
{!sidebarCollapsed && (
|
{!sidebarCollapsed && (
|
||||||
<Menu as="div" className="relative flex-shrink-0">
|
<Menu as="div" className="relative flex-shrink-0">
|
||||||
<MenuButton className="grid place-items-center outline-none" ref={setReferenceElement}>
|
<Menu.Button className="grid place-items-center outline-none" ref={setReferenceElement}>
|
||||||
<Avatar
|
<Avatar
|
||||||
name={currentUser?.display_name}
|
name={currentUser?.display_name}
|
||||||
src={currentUser?.avatar || undefined}
|
src={currentUser?.avatar || undefined}
|
||||||
@ -257,7 +257,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
shape="square"
|
shape="square"
|
||||||
className="!text-base"
|
className="!text-base"
|
||||||
/>
|
/>
|
||||||
</MenuButton>
|
</Menu.Button>
|
||||||
<Transition
|
<Transition
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="transition ease-out duration-100"
|
enter="transition ease-out duration-100"
|
||||||
@ -267,7 +267,7 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
leaveFrom="transform opacity-100 scale-100"
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
leaveTo="transform opacity-0 scale-95"
|
leaveTo="transform opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<MenuItems
|
<Menu.Items
|
||||||
className="absolute left-0 z-20 mt-1 flex w-52 origin-top-left flex-col divide-y
|
className="absolute left-0 z-20 mt-1 flex w-52 origin-top-left flex-col divide-y
|
||||||
divide-custom-sidebar-border-200 rounded-md border border-custom-sidebar-border-200 bg-custom-sidebar-background-100 px-1 py-2 text-xs shadow-lg outline-none"
|
divide-custom-sidebar-border-200 rounded-md border border-custom-sidebar-border-200 bg-custom-sidebar-background-100 px-1 py-2 text-xs shadow-lg outline-none"
|
||||||
ref={setPopperElement as Ref<HTMLDivElement>}
|
ref={setPopperElement as Ref<HTMLDivElement>}
|
||||||
@ -284,17 +284,17 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
if (index == 0) handleItemClick();
|
if (index == 0) handleItemClick();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MenuItem key={index} as="div">
|
<Menu.Item key={index} as="div">
|
||||||
<span className="flex w-full items-center gap-2 rounded px-2 py-1 hover:bg-custom-sidebar-background-80">
|
<span className="flex w-full items-center gap-2 rounded px-2 py-1 hover:bg-custom-sidebar-background-80">
|
||||||
<link.icon className="h-4 w-4 stroke-[1.5]" />
|
<link.icon className="h-4 w-4 stroke-[1.5]" />
|
||||||
{link.name}
|
{link.name}
|
||||||
</span>
|
</span>
|
||||||
</MenuItem>
|
</Menu.Item>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className={`pt-2 ${isUserInstanceAdmin || false ? "pb-2" : ""}`}>
|
<div className={`pt-2 ${isUserInstanceAdmin || false ? "pb-2" : ""}`}>
|
||||||
<MenuItem
|
<Menu.Item
|
||||||
as="button"
|
as="button"
|
||||||
type="button"
|
type="button"
|
||||||
className="flex w-full items-center gap-2 rounded px-2 py-1 hover:bg-custom-sidebar-background-80"
|
className="flex w-full items-center gap-2 rounded px-2 py-1 hover:bg-custom-sidebar-background-80"
|
||||||
@ -302,20 +302,20 @@ export const WorkspaceSidebarDropdown = observer(() => {
|
|||||||
>
|
>
|
||||||
<LogOut className="h-4 w-4 stroke-[1.5]" />
|
<LogOut className="h-4 w-4 stroke-[1.5]" />
|
||||||
Sign out
|
Sign out
|
||||||
</MenuItem>
|
</Menu.Item>
|
||||||
</div>
|
</div>
|
||||||
{isUserInstanceAdmin && (
|
{isUserInstanceAdmin && (
|
||||||
<div className="p-2 pb-0">
|
<div className="p-2 pb-0">
|
||||||
<Link href={GOD_MODE_URL}>
|
<Link href={GOD_MODE_URL}>
|
||||||
<MenuItem as="button" type="button" className="w-full">
|
<Menu.Item as="button" type="button" className="w-full">
|
||||||
<span className="flex w-full items-center justify-center rounded bg-custom-primary-100/20 px-2 py-1 text-sm font-medium text-custom-primary-100 hover:bg-custom-primary-100/30 hover:text-custom-primary-200">
|
<span className="flex w-full items-center justify-center rounded bg-custom-primary-100/20 px-2 py-1 text-sm font-medium text-custom-primary-100 hover:bg-custom-primary-100/30 hover:text-custom-primary-200">
|
||||||
Enter God Mode
|
Enter God Mode
|
||||||
</span>
|
</span>
|
||||||
</MenuItem>
|
</Menu.Item>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</MenuItems>
|
</Menu.Items>
|
||||||
</Transition>
|
</Transition>
|
||||||
</Menu>
|
</Menu>
|
||||||
)}
|
)}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
"@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^1.3.0",
|
"@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^1.3.0",
|
||||||
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
|
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
|
||||||
"@blueprintjs/popover2": "^1.13.3",
|
"@blueprintjs/popover2": "^1.13.3",
|
||||||
"@headlessui/react": "^2.0.4",
|
"@headlessui/react": "^1.7.3",
|
||||||
"@nivo/bar": "0.80.0",
|
"@nivo/bar": "0.80.0",
|
||||||
"@nivo/calendar": "0.80.0",
|
"@nivo/calendar": "0.80.0",
|
||||||
"@nivo/core": "0.80.0",
|
"@nivo/core": "0.80.0",
|
||||||
|
@ -1592,7 +1592,7 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.2.tgz#d8bae93ac8b815b2bd7a98078cf91e2724ef11e5"
|
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.2.tgz#d8bae93ac8b815b2bd7a98078cf91e2724ef11e5"
|
||||||
integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==
|
integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==
|
||||||
|
|
||||||
"@headlessui/react@^1.7.13", "@headlessui/react@^1.7.19":
|
"@headlessui/react@^1.7.13", "@headlessui/react@^1.7.19", "@headlessui/react@^1.7.3":
|
||||||
version "1.7.19"
|
version "1.7.19"
|
||||||
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.19.tgz#91c78cf5fcb254f4a0ebe96936d48421caf75f40"
|
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.19.tgz#91c78cf5fcb254f4a0ebe96936d48421caf75f40"
|
||||||
integrity sha512-Ll+8q3OlMJfJbAKM/+/Y2q6PPYbryqNTXDbryx7SXLIDamkF6iQFbriYHga0dY44PvDhvvBWCx1Xj4U5+G4hOw==
|
integrity sha512-Ll+8q3OlMJfJbAKM/+/Y2q6PPYbryqNTXDbryx7SXLIDamkF6iQFbriYHga0dY44PvDhvvBWCx1Xj4U5+G4hOw==
|
||||||
@ -1600,7 +1600,7 @@
|
|||||||
"@tanstack/react-virtual" "^3.0.0-beta.60"
|
"@tanstack/react-virtual" "^3.0.0-beta.60"
|
||||||
client-only "^0.0.1"
|
client-only "^0.0.1"
|
||||||
|
|
||||||
"@headlessui/react@^2.0.3", "@headlessui/react@^2.0.4":
|
"@headlessui/react@^2.0.3":
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-2.0.4.tgz#46cb39ca9dde3c2d15f4706c81dad78405b608f0"
|
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-2.0.4.tgz#46cb39ca9dde3c2d15f4706c81dad78405b608f0"
|
||||||
integrity sha512-16d/rOLeYsFsmPlRmXGu8DCBzrWD0zV1Ccx3n73wN87yFu8Y9+X04zflv8EJEt9TAYRyLKOmQXUnOnqQl6NgpA==
|
integrity sha512-16d/rOLeYsFsmPlRmXGu8DCBzrWD0zV1Ccx3n73wN87yFu8Y9+X04zflv8EJEt9TAYRyLKOmQXUnOnqQl6NgpA==
|
||||||
|
Loading…
Reference in New Issue
Block a user