chore: store setup

This commit is contained in:
sriram veeraghanta 2023-09-20 20:33:25 +05:30
parent 50c330db65
commit a328c530d0
161 changed files with 1389 additions and 2775 deletions

View File

@ -7,19 +7,14 @@ import analyticsService from "services/analytics.service";
import projectService from "services/project.service";
import cyclesService from "services/cycles.service";
import modulesService from "services/modules.service";
import trackEventServices from "services/track-event.service";
import trackEventServices from "services/track_event.service";
// hooks
import useProjects from "hooks/use-projects";
import useToast from "hooks/use-toast";
// ui
import { PrimaryButton, SecondaryButton } from "components/ui";
// icons
import {
ArrowDownTrayIcon,
ArrowPathIcon,
CalendarDaysIcon,
UserGroupIcon,
} from "@heroicons/react/24/outline";
import { ArrowDownTrayIcon, ArrowPathIcon, CalendarDaysIcon, UserGroupIcon } from "@heroicons/react/24/outline";
import { ContrastIcon, LayerDiagonalIcon } from "components/icons";
// helpers
import { renderShortDate } from "helpers/date-time.helper";
@ -46,13 +41,7 @@ type Props = {
user: ICurrentUserResponse | undefined;
};
export const AnalyticsSidebar: React.FC<Props> = ({
analytics,
params,
fullScreen,
isProjectLevel = false,
user,
}) => {
export const AnalyticsSidebar: React.FC<Props> = ({ analytics, params, fullScreen, isProjectLevel = false, user }) => {
const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
@ -61,9 +50,7 @@ export const AnalyticsSidebar: React.FC<Props> = ({
const { setToastAlert } = useToast();
const { data: projectDetails } = useSWR(
workspaceSlug && projectId && !(cycleId || moduleId)
? PROJECT_DETAILS(projectId.toString())
: null,
workspaceSlug && projectId && !(cycleId || moduleId) ? PROJECT_DETAILS(projectId.toString()) : null,
workspaceSlug && projectId && !(cycleId || moduleId)
? () => projectService.getProject(workspaceSlug.toString(), projectId.toString())
: null
@ -72,24 +59,14 @@ export const AnalyticsSidebar: React.FC<Props> = ({
const { data: cycleDetails } = useSWR(
workspaceSlug && projectId && cycleId ? CYCLE_DETAILS(cycleId.toString()) : null,
workspaceSlug && projectId && cycleId
? () =>
cyclesService.getCycleDetails(
workspaceSlug.toString(),
projectId.toString(),
cycleId.toString()
)
? () => cyclesService.getCycleDetails(workspaceSlug.toString(), projectId.toString(), cycleId.toString())
: null
);
const { data: moduleDetails } = useSWR(
workspaceSlug && projectId && moduleId ? MODULE_DETAILS(moduleId.toString()) : null,
workspaceSlug && projectId && moduleId
? () =>
modulesService.getModuleDetails(
workspaceSlug.toString(),
projectId.toString(),
moduleId.toString()
)
? () => modulesService.getModuleDetails(workspaceSlug.toString(), projectId.toString(), moduleId.toString())
: null
);
@ -178,8 +155,7 @@ export const AnalyticsSidebar: React.FC<Props> = ({
);
};
const selectedProjects =
params.project && params.project.length > 0 ? params.project : projects?.map((p) => p.id);
const selectedProjects = params.project && params.project.length > 0 ? params.project : projects?.map((p) => p.id);
return (
<div
@ -236,9 +212,7 @@ export const AnalyticsSidebar: React.FC<Props> = ({
)}
<h5 className="flex items-center gap-1">
<p className="break-words">{truncateText(project.name, 20)}</p>
<span className="text-custom-text-200 text-xs ml-1">
({project.identifier})
</span>
<span className="text-custom-text-200 text-xs ml-1">({project.identifier})</span>
</h5>
</div>
<div className="mt-4 space-y-3 pl-2 w-full">
@ -344,10 +318,7 @@ export const AnalyticsSidebar: React.FC<Props> = ({
<div className="space-y-4 mt-4">
<div className="flex items-center gap-2 text-xs">
<h6 className="text-custom-text-200">Network</h6>
<span>
{NETWORK_CHOICES.find((n) => n.key === projectDetails?.network)?.label ??
""}
</span>
<span>{NETWORK_CHOICES.find((n) => n.key === projectDetails?.network)?.label ?? ""}</span>
</div>
</div>
</div>

View File

@ -13,15 +13,11 @@ import analyticsService from "services/analytics.service";
import projectService from "services/project.service";
import cyclesService from "services/cycles.service";
import modulesService from "services/modules.service";
import trackEventServices from "services/track-event.service";
import trackEventServices from "services/track_event.service";
// components
import { CustomAnalytics, ScopeAndDemand } from "components/analytics";
// icons
import {
ArrowsPointingInIcon,
ArrowsPointingOutIcon,
XMarkIcon,
} from "@heroicons/react/24/outline";
import { ArrowsPointingInIcon, ArrowsPointingOutIcon, XMarkIcon } from "@heroicons/react/24/outline";
// types
import { IAnalyticsParams, IWorkspace } from "types";
// fetch-keys
@ -67,9 +63,7 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
);
const { data: projectDetails } = useSWR(
workspaceSlug && projectId && !(cycleId || moduleId)
? PROJECT_DETAILS(projectId.toString())
: null,
workspaceSlug && projectId && !(cycleId || moduleId) ? PROJECT_DETAILS(projectId.toString()) : null,
workspaceSlug && projectId && !(cycleId || moduleId)
? () => projectService.getProject(workspaceSlug.toString(), projectId.toString())
: null
@ -78,24 +72,14 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
const { data: cycleDetails } = useSWR(
workspaceSlug && projectId && cycleId ? CYCLE_DETAILS(cycleId.toString()) : null,
workspaceSlug && projectId && cycleId
? () =>
cyclesService.getCycleDetails(
workspaceSlug.toString(),
projectId.toString(),
cycleId.toString()
)
? () => cyclesService.getCycleDetails(workspaceSlug.toString(), projectId.toString(), cycleId.toString())
: null
);
const { data: moduleDetails } = useSWR(
workspaceSlug && projectId && moduleId ? MODULE_DETAILS(moduleId.toString()) : null,
workspaceSlug && projectId && moduleId
? () =>
modulesService.getModuleDetails(
workspaceSlug.toString(),
projectId.toString(),
moduleId.toString()
)
? () => modulesService.getModuleDetails(workspaceSlug.toString(), projectId.toString(), moduleId.toString())
: null
);
@ -134,8 +118,7 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
eventPayload.moduleName = moduleDetails.name;
}
const eventType =
tab === "Scope and Demand" ? "SCOPE_AND_DEMAND_ANALYTICS" : "CUSTOM_ANALYTICS";
const eventType = tab === "Scope and Demand" ? "SCOPE_AND_DEMAND_ANALYTICS" : "CUSTOM_ANALYTICS";
trackEventServices.trackAnalyticsEvent(
eventPayload,
@ -150,9 +133,9 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
return (
<div
className={`absolute top-0 z-30 h-full bg-custom-background-90 ${
fullScreen ? "p-2 w-full" : "w-1/2"
} ${isOpen ? "right-0" : "-right-full"} duration-300 transition-all`}
className={`absolute top-0 z-30 h-full bg-custom-background-90 ${fullScreen ? "p-2 w-full" : "w-1/2"} ${
isOpen ? "right-0" : "-right-full"
} duration-300 transition-all`}
>
<div
className={`flex h-full flex-col overflow-hidden border-custom-border-200 bg-custom-background-100 text-left ${
@ -161,8 +144,7 @@ export const AnalyticsProjectModal: React.FC<Props> = ({ isOpen, onClose }) => {
>
<div className="flex items-center justify-between gap-4 bg-custom-background-100 px-5 py-4 text-sm">
<h3 className="break-words">
Analytics for{" "}
{cycleId ? cycleDetails?.name : moduleId ? moduleDetails?.name : projectDetails?.name}
Analytics for {cycleId ? cycleDetails?.name : moduleId ? moduleDetails?.name : projectDetails?.name}
</h3>
<div className="flex items-center gap-2">
<button

View File

@ -12,7 +12,7 @@ import { Squares2X2Icon } from "@heroicons/react/24/outline";
import { StateGroupIcon } from "components/icons";
import { ArchiveX } from "lucide-react";
// services
import stateService from "services/state.service";
import stateService from "services/project_state.service";
// constants
import { PROJECT_AUTOMATION_MONTHS } from "constants/project";
import { STATES_LIST } from "constants/fetch-keys";
@ -34,9 +34,7 @@ export const AutoCloseAutomation: React.FC<Props> = ({ projectDetails, handleCha
const { data: stateGroups } = useSWR(
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
workspaceSlug && projectId
? () => stateService.getStates(workspaceSlug as string, projectId as string)
: null
workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null
);
const states = getStatesList(stateGroups);
@ -57,9 +55,7 @@ export const AutoCloseAutomation: React.FC<Props> = ({ projectDetails, handleCha
const defaultState = stateGroups && stateGroups.cancelled ? stateGroups.cancelled[0].id : null;
const selectedOption = states?.find(
(s) => s.id === projectDetails?.default_state ?? defaultState
);
const selectedOption = states?.find((s) => s.id === projectDetails?.default_state ?? defaultState);
const currentDefaultState = states?.find((s) => s.id === defaultState);
const initialValues: Partial<IProject> = {
@ -105,15 +101,11 @@ export const AutoCloseAutomation: React.FC<Props> = ({ projectDetails, handleCha
<div className="ml-12">
<div className="flex flex-col rounded bg-custom-background-90 border border-custom-border-200 p-2">
<div className="flex items-center justify-between px-5 py-4 gap-2 w-full">
<div className="w-1/2 text-sm font-medium">
Auto-close issues that are inactive for
</div>
<div className="w-1/2 text-sm font-medium">Auto-close issues that are inactive for</div>
<div className="w-1/2">
<CustomSelect
value={projectDetails?.close_in}
label={`${projectDetails?.close_in} ${
projectDetails?.close_in === 1 ? "Month" : "Months"
}`}
label={`${projectDetails?.close_in} ${projectDetails?.close_in === 1 ? "Month" : "Months"}`}
onChange={(val: number) => {
handleChange({ close_in: val });
}}
@ -142,9 +134,7 @@ export const AutoCloseAutomation: React.FC<Props> = ({ projectDetails, handleCha
<div className="w-1/2 text-sm font-medium">Auto-close Status</div>
<div className="w-1/2 ">
<CustomSearchSelect
value={
projectDetails?.default_state ? projectDetails?.default_state : defaultState
}
value={projectDetails?.default_state ? projectDetails?.default_state : defaultState}
label={
<div className="flex items-center gap-2">
{selectedOption ? (
@ -166,9 +156,7 @@ export const AutoCloseAutomation: React.FC<Props> = ({ projectDetails, handleCha
)}
{selectedOption?.name
? selectedOption.name
: currentDefaultState?.name ?? (
<span className="text-custom-text-200">State</span>
)}
: currentDefaultState?.name ?? <span className="text-custom-text-200">State</span>}
</div>
}
onChange={(val: string) => {

View File

@ -10,7 +10,7 @@ import { Command } from "cmdk";
import { Dialog, Transition } from "@headlessui/react";
// services
import workspaceService from "services/workspace.service";
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
import inboxService from "services/inbox.service";
// hooks
import useProjectDetails from "hooks/use-project-details";
@ -79,16 +79,13 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
const { data: issueDetails } = useSWR(
workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null,
workspaceSlug && projectId && issueId
? () =>
issuesService.retrieve(workspaceSlug as string, projectId as string, issueId as string)
? () => issuesService.retrieve(workspaceSlug as string, projectId as string, issueId as string)
: null
);
const { data: inboxList } = useSWR(
workspaceSlug && projectId ? INBOX_LIST(projectId as string) : null,
workspaceSlug && projectId
? () => inboxService.getInboxes(workspaceSlug as string, projectId as string)
: null
workspaceSlug && projectId ? () => inboxService.getInboxes(workspaceSlug as string, projectId as string) : null
);
const updateIssue = useCallback(
@ -272,8 +269,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
>
{issueDetails && (
<div className="overflow-hidden truncate rounded-md bg-custom-background-80 p-2 text-xs font-medium text-custom-text-200">
{issueDetails.project_detail.identifier}-{issueDetails.sequence_id}{" "}
{issueDetails.name}
{issueDetails.project_detail.identifier}-{issueDetails.sequence_id} {issueDetails.name}
</div>
)}
{projectId && (
@ -324,12 +320,9 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
</h5>
)}
{!isLoading &&
resultsCount === 0 &&
searchTerm !== "" &&
debouncedSearchTerm !== "" && (
<div className="my-4 text-center text-custom-text-200">No results found.</div>
)}
{!isLoading && resultsCount === 0 && searchTerm !== "" && debouncedSearchTerm !== "" && (
<div className="my-4 text-center text-custom-text-200">No results found.</div>
)}
{(isLoading || isSearching) && (
<Command.Loading>
@ -362,9 +355,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
>
<div className="flex items-center gap-2 overflow-hidden text-custom-text-200">
<Icon iconName={currentSection.icon} />
<p className="block flex-1 truncate">
{currentSection.itemName(item)}
</p>
<p className="block flex-1 truncate">{currentSection.itemName(item)}</p>
</div>
</Command.Item>
))}
@ -577,9 +568,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
<Command.Item
onSelect={() => {
setIsPaletteOpen(false);
redirect(
`/${workspaceSlug}/projects/${projectId}/inbox/${inboxList?.[0]?.id}`
);
redirect(`/${workspaceSlug}/projects/${projectId}/inbox/${inboxList?.[0]?.id}`);
}}
className="focus:outline-none"
>
@ -672,10 +661,7 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
<Command.Item
onSelect={() => {
setIsPaletteOpen(false);
window.open(
"https://github.com/makeplane/plane/issues/new/choose",
"_blank"
);
window.open("https://github.com/makeplane/plane/issues/new/choose", "_blank");
}}
className="focus:outline-none"
>
@ -759,29 +745,15 @@ export const CommandK: React.FC<Props> = ({ deleteIssue, isPaletteOpen, setIsPal
</>
)}
{page === "change-issue-state" && issueDetails && (
<ChangeIssueState
issue={issueDetails}
setIsPaletteOpen={setIsPaletteOpen}
user={user}
/>
<ChangeIssueState issue={issueDetails} setIsPaletteOpen={setIsPaletteOpen} user={user} />
)}
{page === "change-issue-priority" && issueDetails && (
<ChangeIssuePriority
issue={issueDetails}
setIsPaletteOpen={setIsPaletteOpen}
user={user}
/>
<ChangeIssuePriority issue={issueDetails} setIsPaletteOpen={setIsPaletteOpen} user={user} />
)}
{page === "change-issue-assignee" && issueDetails && (
<ChangeIssueAssignee
issue={issueDetails}
setIsPaletteOpen={setIsPaletteOpen}
user={user}
/>
)}
{page === "change-interface-theme" && (
<ChangeInterfaceTheme setIsPaletteOpen={setIsPaletteOpen} />
<ChangeIssueAssignee issue={issueDetails} setIsPaletteOpen={setIsPaletteOpen} user={user} />
)}
{page === "change-interface-theme" && <ChangeInterfaceTheme setIsPaletteOpen={setIsPaletteOpen} />}
</Command.List>
</Command>
</Dialog.Panel>

View File

@ -17,7 +17,7 @@ import { CreateUpdatePageModal } from "components/pages";
// helpers
import { copyTextToClipboard } from "helpers/string.helper";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
import inboxService from "services/inbox.service";
// fetch keys
import { INBOX_LIST, ISSUE_DETAILS } from "constants/fetch-keys";
@ -50,8 +50,7 @@ export const CommandPalette: React.FC = observer(() => {
const { data: issueDetails } = useSWR(
workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null,
workspaceSlug && projectId && issueId
? () =>
issuesService.retrieve(workspaceSlug as string, projectId as string, issueId as string)
? () => issuesService.retrieve(workspaceSlug as string, projectId as string, issueId as string)
: null
);
@ -141,11 +140,7 @@ export const CommandPalette: React.FC = observer(() => {
<>
<ShortcutsModal isOpen={isShortcutsModalOpen} setIsOpen={setIsShortcutsModalOpen} />
{workspaceSlug && (
<CreateProjectModal
isOpen={isProjectModalOpen}
setIsOpen={setIsProjectModalOpen}
user={user}
/>
<CreateProjectModal isOpen={isProjectModalOpen} setIsOpen={setIsProjectModalOpen} user={user} />
)}
{projectId && (
<>
@ -184,11 +179,7 @@ export const CommandPalette: React.FC = observer(() => {
handleClose={() => setIsIssueModalOpen(false)}
fieldsToShow={inboxId ? ["name", "description", "priority"] : ["all"]}
prePopulateData={
cycleId
? { cycle: cycleId.toString() }
: moduleId
? { module: moduleId.toString() }
: undefined
cycleId ? { cycle: cycleId.toString() } : moduleId ? { module: moduleId.toString() } : undefined
}
/>
<BulkDeleteIssuesModal
@ -196,11 +187,7 @@ export const CommandPalette: React.FC = observer(() => {
setIsOpen={setIsBulkDeleteIssuesModalOpen}
user={user}
/>
<CommandK
deleteIssue={deleteIssue}
isPaletteOpen={isPaletteOpen}
setIsPaletteOpen={setIsPaletteOpen}
/>
<CommandK deleteIssue={deleteIssue} isPaletteOpen={isPaletteOpen} setIsPaletteOpen={setIsPaletteOpen} />
</>
);
});

View File

@ -7,7 +7,7 @@ import { mutate } from "swr";
// cmdk
import { Command } from "cmdk";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useProjectMembers from "hooks/use-project-members";
// constants

View File

@ -7,7 +7,7 @@ import { mutate } from "swr";
// cmdk
import { Command } from "cmdk";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// types
import { ICurrentUserResponse, IIssue, TIssuePriorities } from "types";
// constants
@ -64,11 +64,7 @@ export const ChangeIssuePriority: React.FC<Props> = ({ setIsPaletteOpen, issue,
return (
<>
{PRIORITIES.map((priority) => (
<Command.Item
key={priority}
onSelect={() => handleIssueState(priority)}
className="focus:outline-none"
>
<Command.Item key={priority} onSelect={() => handleIssueState(priority)} className="focus:outline-none">
<div className="flex items-center space-x-3">
<PriorityIcon priority={priority} />
<span className="capitalize">{priority ?? "None"}</span>

View File

@ -7,8 +7,8 @@ import useSWR, { mutate } from "swr";
// cmdk
import { Command } from "cmdk";
// services
import issuesService from "services/issues.service";
import stateService from "services/state.service";
import issuesService from "services/issue.service";
import stateService from "services/project_state.service";
// ui
import { Spinner } from "components/ui";
// icons
@ -32,9 +32,7 @@ export const ChangeIssueState: React.FC<Props> = ({ setIsPaletteOpen, issue, use
const { data: stateGroups, mutate: mutateIssueDetails } = useSWR(
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
workspaceSlug && projectId
? () => stateService.getStates(workspaceSlug as string, projectId as string)
: null
workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null
);
const states = getStatesList(stateGroups);
@ -78,18 +76,9 @@ export const ChangeIssueState: React.FC<Props> = ({ setIsPaletteOpen, issue, use
{states ? (
states.length > 0 ? (
states.map((state) => (
<Command.Item
key={state.id}
onSelect={() => handleIssueState(state.id)}
className="focus:outline-none"
>
<Command.Item key={state.id} onSelect={() => handleIssueState(state.id)} className="focus:outline-none">
<div className="flex items-center space-x-3">
<StateGroupIcon
stateGroup={state.group}
color={state.color}
height="16px"
width="16px"
/>
<StateGroupIcon stateGroup={state.group} color={state.color} height="16px" width="16px" />
<p>{state.name}</p>
</div>
<div>{state.id === issue.state && <CheckIcon className="h-3 w-3" />}</div>

View File

@ -9,7 +9,7 @@ import { SubmitHandler, useForm } from "react-hook-form";
// headless ui
import { Combobox, Dialog, Transition } from "@headlessui/react";
// services
import issuesServices from "services/issues.service";
import issuesServices from "services/issue.service";
// hooks
import useToast from "hooks/use-toast";
import useIssuesView from "hooks/use-issues-view";
@ -49,12 +49,8 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
const { data: issues } = useSWR(
workspaceSlug && projectId
? PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)
: null,
workspaceSlug && projectId
? () => issuesServices.getIssues(workspaceSlug as string, projectId as string)
: null
workspaceSlug && projectId ? PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string) : null,
workspaceSlug && projectId ? () => issuesServices.getIssues(workspaceSlug as string, projectId as string) : null
);
const { setToastAlert } = useToast();
@ -155,9 +151,7 @@ export const BulkDeleteIssuesModal: React.FC<Props> = ({ isOpen, setIsOpen, user
: issues?.filter(
(issue) =>
issue.name.toLowerCase().includes(query.toLowerCase()) ||
`${issue.project_detail.identifier}-${issue.sequence_id}`
.toLowerCase()
.includes(query.toLowerCase())
`${issue.project_detail.identifier}-${issue.sequence_id}`.toLowerCase().includes(query.toLowerCase())
) ?? [];
return (

View File

@ -4,7 +4,7 @@ import { useRouter } from "next/router";
import { useForm } from "react-hook-form";
// services
import aiService from "services/ai.service";
import trackEventServices from "services/track-event.service";
import trackEventServices from "services/track_event.service";
// hooks
import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
@ -110,9 +110,7 @@ export const GptAssistantModal: React.FC<Props> = ({
setToastAlert({
type: "error",
title: "Error!",
message:
error ||
"You have reached the maximum number of requests of 50 requests per month per user.",
message: error || "You have reached the maximum number of requests of 50 requests per month per user.",
});
else
setToastAlert({
@ -166,8 +164,7 @@ export const GptAssistantModal: React.FC<Props> = ({
)}
{invalidResponse && (
<div className="text-sm text-red-500">
No response could be generated. This may be due to insufficient content or task
information. Please try again.
No response could be generated. This may be due to insufficient content or task information. Please try again.
</div>
)}
<Input
@ -175,9 +172,7 @@ export const GptAssistantModal: React.FC<Props> = ({
name="task"
register={register}
placeholder={`${
content && content !== ""
? "Tell AI what action to perform on this content..."
: "Ask AI anything..."
content && content !== "" ? "Tell AI what action to perform on this content..." : "Ask AI anything..."
}`}
autoComplete="off"
/>
@ -187,18 +182,8 @@ export const GptAssistantModal: React.FC<Props> = ({
onClick={() => {
onResponse(response);
onClose();
if (block)
trackEventServices.trackUseGPTResponseEvent(
block,
"USE_GPT_RESPONSE_IN_PAGE_BLOCK",
user
);
else if (issue)
trackEventServices.trackUseGPTResponseEvent(
issue,
"USE_GPT_RESPONSE_IN_ISSUE",
user
);
if (block) trackEventServices.trackUseGPTResponseEvent(block, "USE_GPT_RESPONSE_IN_PAGE_BLOCK", user);
else if (issue) trackEventServices.trackUseGPTResponseEvent(issue, "USE_GPT_RESPONSE_IN_ISSUE", user);
}}
>
Use this response
@ -206,16 +191,8 @@ export const GptAssistantModal: React.FC<Props> = ({
)}
<div className="flex items-center gap-2">
<SecondaryButton onClick={onClose}>Close</SecondaryButton>
<PrimaryButton
type="button"
onClick={handleSubmit(handleResponse)}
loading={isSubmitting}
>
{isSubmitting
? "Generating response..."
: response === ""
? "Generate response"
: "Generate again"}
<PrimaryButton type="button" onClick={handleSubmit(handleResponse)} loading={isSubmitting}>
{isSubmitting ? "Generating response..." : response === "" ? "Generate response" : "Generate again"}
</PrimaryButton>
</div>
</div>

View File

@ -8,18 +8,12 @@ import useSWR from "swr";
import { DragDropContext, DropResult } from "react-beautiful-dnd";
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
// services
import stateService from "services/state.service";
import stateService from "services/project_state.service";
// hooks
import useUser from "hooks/use-user";
import { useProjectMyMembership } from "contexts/project-member.context";
// components
import {
AllLists,
AllBoards,
CalendarView,
SpreadsheetView,
GanttChartView,
} from "components/core";
import { AllLists, AllBoards, CalendarView, SpreadsheetView, GanttChartView } from "components/core";
// ui
import { EmptyState, Spinner } from "components/ui";
// icons
@ -88,9 +82,7 @@ export const AllViews: React.FC<Props> = ({
const { data: stateGroups } = useSWR(
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
workspaceSlug
? () => stateService.getStates(workspaceSlug as string, projectId as string)
: null
workspaceSlug ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null
);
const states = getStatesList(stateGroups);
@ -180,9 +172,7 @@ export const AllViews: React.FC<Props> = ({
userAuth={memberRole}
/>
) : (
displayFilters?.layout === "gantt_chart" && (
<GanttChartView disableUserActions={disableUserActions} />
)
displayFilters?.layout === "gantt_chart" && <GanttChartView disableUserActions={disableUserActions} />
)}
</>
) : router.pathname.includes("archived-issues") ? (

View File

@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
import projectService from "services/project.service";
// hooks
import useProjects from "hooks/use-projects";
@ -106,12 +106,7 @@ export const BoardHeader: React.FC<Props> = ({
switch (displayFilters?.group_by) {
case "state":
icon = currentState && (
<StateGroupIcon
stateGroup={currentState.group}
color={currentState.color}
height="16px"
width="16px"
/>
<StateGroupIcon stateGroup={currentState.group} color={currentState.color} height="16px" width="16px" />
);
break;
case "state_detail.group":
@ -138,14 +133,8 @@ export const BoardHeader: React.FC<Props> = ({
: null);
break;
case "labels":
const labelColor =
issueLabels?.find((label) => label.id === groupTitle)?.color ?? "#000000";
icon = (
<span
className="h-3.5 w-3.5 flex-shrink-0 rounded-full"
style={{ backgroundColor: labelColor }}
/>
);
const labelColor = issueLabels?.find((label) => label.id === groupTitle)?.color ?? "#000000";
icon = <span className="h-3.5 w-3.5 flex-shrink-0 rounded-full" style={{ backgroundColor: labelColor }} />;
break;
case "assignees":
case "created_by":
@ -196,10 +185,7 @@ export const BoardHeader: React.FC<Props> = ({
}}
>
{isCollapsed ? (
<Icon
iconName="close_fullscreen"
className="text-base font-medium text-custom-text-900"
/>
<Icon iconName="close_fullscreen" className="text-base font-medium text-custom-text-900" />
) : (
<Icon iconName="open_in_full" className="text-base font-medium text-custom-text-900" />
)}

View File

@ -5,14 +5,9 @@ import { useRouter } from "next/router";
import { mutate } from "swr";
// react-beautiful-dnd
import {
DraggableProvided,
DraggableStateSnapshot,
DraggingStyle,
NotDraggingStyle,
} from "react-beautiful-dnd";
import { DraggableProvided, DraggableStateSnapshot, DraggingStyle, NotDraggingStyle } from "react-beautiful-dnd";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useToast from "hooks/use-toast";
import useOutsideClickDetector from "hooks/use-outside-click-detector";
@ -147,22 +142,17 @@ export const SingleBoardIssue: React.FC<Props> = ({
);
}
issuesService
.patchIssue(workspaceSlug as string, issue.project, issue.id, formData, user)
.then(() => {
mutateIssues();
issuesService.patchIssue(workspaceSlug as string, issue.project, issue.id, formData, user).then(() => {
mutateIssues();
if (cycleId) mutate(CYCLE_DETAILS(cycleId as string));
if (moduleId) mutate(MODULE_DETAILS(moduleId as string));
});
if (cycleId) mutate(CYCLE_DETAILS(cycleId as string));
if (moduleId) mutate(MODULE_DETAILS(moduleId as string));
});
},
[displayFilters, workspaceSlug, cycleId, moduleId, groupTitle, index, mutateIssues, user]
);
const getStyle = (
style: DraggingStyle | NotDraggingStyle | undefined,
snapshot: DraggableStateSnapshot
) => {
const getStyle = (style: DraggingStyle | NotDraggingStyle | undefined, snapshot: DraggableStateSnapshot) => {
if (displayFilters?.order_by === "sort_order") return style;
if (!snapshot.isDragging) return {};
if (!snapshot.isDropAnimating) return style;
@ -174,11 +164,8 @@ export const SingleBoardIssue: React.FC<Props> = ({
};
const handleCopyText = () => {
const originURL =
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
copyTextToClipboard(
`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`
).then(() => {
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`).then(() => {
setToastAlert({
type: "success",
title: "Link Copied!",
@ -253,9 +240,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
target="_blank"
rel="noreferrer noopener"
>
<ContextMenu.Item Icon={ArrowTopRightOnSquareIcon}>
Open issue in new tab
</ContextMenu.Item>
<ContextMenu.Item Icon={ArrowTopRightOnSquareIcon}>Open issue in new tab</ContextMenu.Item>
</a>
)}
</ContextMenu>
@ -277,9 +262,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
{!isNotAllowed && (
<div
ref={actionSectionRef}
className={`z-1 absolute top-1.5 right-1.5 hidden group-hover/card:!flex ${
isMenuActive ? "!flex" : ""
}`}
className={`z-1 absolute top-1.5 right-1.5 hidden group-hover/card:!flex ${isMenuActive ? "!flex" : ""}`}
>
{type && !isNotAllowed && (
<CustomMenu
@ -353,11 +336,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
</button>
</div>
<div
className={`flex items-center gap-2 text-xs ${
isDropdownActive ? "" : "overflow-x-scroll"
}`}
>
<div className={`flex items-center gap-2 text-xs ${isDropdownActive ? "" : "overflow-x-scroll"}`}>
{properties.priority && (
<ViewPrioritySelect
issue={issue}

View File

@ -7,7 +7,7 @@ import { mutate } from "swr";
// react-beautiful-dnd
import { DragDropContext, DropResult } from "react-beautiful-dnd";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useCalendarIssuesView from "hooks/use-calendar-issues-view";
// components
@ -17,13 +17,7 @@ import { IssuePeekOverview } from "components/issues";
import { Spinner } from "components/ui";
// helpers
import { renderDateFormat } from "helpers/date-time.helper";
import {
startOfWeek,
lastDayOfWeek,
eachDayOfInterval,
weekDayInterval,
formatDate,
} from "helpers/calendar.helper";
import { startOfWeek, lastDayOfWeek, eachDayOfInterval, weekDayInterval, formatDate } from "helpers/calendar.helper";
// types
import { ICalendarRange, ICurrentUserResponse, IIssue, UserAuth } from "types";
// fetch-keys
@ -61,8 +55,7 @@ export const CalendarView: React.FC<Props> = ({
const router = useRouter();
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
const { calendarIssues, mutateIssues, params, displayFilters, setDisplayFilters } =
useCalendarIssuesView();
const { calendarIssues, mutateIssues, params, displayFilters, setDisplayFilters } = useCalendarIssuesView();
const totalDate = eachDayOfInterval({
start: calendarDates.startDate,
@ -80,8 +73,7 @@ export const CalendarView: React.FC<Props> = ({
const filterIssue =
calendarIssues.length > 0
? calendarIssues.filter(
(issue) =>
issue.target_date && renderDateFormat(issue.target_date) === renderDateFormat(date)
(issue) => issue.target_date && renderDateFormat(issue.target_date) === renderDateFormat(date)
)
: [];
return {
@ -155,18 +147,16 @@ export const CalendarView: React.FC<Props> = ({
});
setDisplayFilters({
calendar_date_range: `${renderDateFormat(startDate)};after,${renderDateFormat(
endDate
)};before`,
calendar_date_range: `${renderDateFormat(startDate)};after,${renderDateFormat(endDate)};before`,
});
};
useEffect(() => {
if (!displayFilters || displayFilters.calendar_date_range === "")
setDisplayFilters({
calendar_date_range: `${renderDateFormat(
startOfWeek(currentDate)
)};after,${renderDateFormat(lastDayOfWeek(currentDate))};before`,
calendar_date_range: `${renderDateFormat(startOfWeek(currentDate))};after,${renderDateFormat(
lastDayOfWeek(currentDate)
)};before`,
});
}, [currentDate, displayFilters, setDisplayFilters]);
@ -214,11 +204,7 @@ export const CalendarView: React.FC<Props> = ({
: ""
}`}
>
<span>
{isMonthlyView
? formatDate(date, "eee").substring(0, 3)
: formatDate(date, "eee")}
</span>
<span>{isMonthlyView ? formatDate(date, "eee").substring(0, 3) : formatDate(date, "eee")}</span>
{!isMonthlyView && <span>{formatDate(date, "d")}</span>}
</div>
))}

View File

@ -7,7 +7,7 @@ import { mutate } from "swr";
// react-beautiful-dnd
import { DraggableProvided, DraggableStateSnapshot } from "react-beautiful-dnd";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useCalendarIssuesView from "hooks/use-calendar-issues-view";
import useIssuesProperties from "hooks/use-issue-properties";
@ -122,13 +122,7 @@ export const SingleCalendarIssue: React.FC<Props> = ({
}
issuesService
.patchIssue(
workspaceSlug as string,
projectId as string,
issue.id as string,
formData,
user
)
.patchIssue(workspaceSlug as string, projectId as string, issue.id as string, formData, user)
.then(() => {
mutate(fetchKey);
})
@ -140,11 +134,8 @@ export const SingleCalendarIssue: React.FC<Props> = ({
);
const handleCopyText = () => {
const originURL =
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
copyTextToClipboard(
`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`
).then(() => {
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`).then(() => {
setToastAlert({
type: "success",
title: "Link Copied!",
@ -153,9 +144,7 @@ export const SingleCalendarIssue: React.FC<Props> = ({
});
};
const displayProperties = properties
? Object.values(properties).some((value) => value === true)
: false;
const displayProperties = properties ? Object.values(properties).some((value) => value === true) : false;
const openPeekOverview = () => {
const { query } = router;

View File

@ -7,10 +7,10 @@ import useSWR, { mutate } from "swr";
// react-beautiful-dnd
import { DropResult } from "react-beautiful-dnd";
// services
import issuesService from "services/issues.service";
import stateService from "services/state.service";
import issuesService from "services/issue.service";
import stateService from "services/project_state.service";
import modulesService from "services/modules.service";
import trackEventServices from "services/track-event.service";
import trackEventServices from "services/track_event.service";
// hooks
import useToast from "hooks/use-toast";
import useIssuesView from "hooks/use-issues-view";
@ -51,10 +51,7 @@ type Props = {
disableUserActions?: boolean;
};
export const IssuesView: React.FC<Props> = ({
openIssuesListModal,
disableUserActions = false,
}) => {
export const IssuesView: React.FC<Props> = ({ openIssuesListModal, disableUserActions = false }) => {
// create issue modal
const [createIssueModal, setCreateIssueModal] = useState(false);
const [createViewModal, setCreateViewModal] = useState<any>(null);
@ -64,9 +61,7 @@ export const IssuesView: React.FC<Props> = ({
// update issue modal
const [editIssueModal, setEditIssueModal] = useState(false);
const [issueToEdit, setIssueToEdit] = useState<
(IIssue & { actionType: "edit" | "delete" }) | undefined
>(undefined);
const [issueToEdit, setIssueToEdit] = useState<(IIssue & { actionType: "edit" | "delete" }) | undefined>(undefined);
// delete issue modal
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
@ -87,15 +82,12 @@ export const IssuesView: React.FC<Props> = ({
const { setToastAlert } = useToast();
const { groupedByIssues, mutateIssues, displayFilters, filters, isEmpty, setFilters, params } =
useIssuesView();
const { groupedByIssues, mutateIssues, displayFilters, filters, isEmpty, setFilters, params } = useIssuesView();
const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string);
const { data: stateGroups } = useSWR(
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
workspaceSlug
? () => stateService.getStates(workspaceSlug as string, projectId as string)
: null
workspaceSlug ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null
);
const states = getStatesList(stateGroups);
@ -141,12 +133,10 @@ export const IssuesView: React.FC<Props> = ({
// check if dropping in the same group
if (source.droppableId === destination.droppableId) {
// check if dropping at beginning
if (destination.index === 0)
newSortOrder = destinationGroupArray[0].sort_order - 10000;
if (destination.index === 0) newSortOrder = destinationGroupArray[0].sort_order - 10000;
// check if dropping at last
else if (destination.index === destinationGroupArray.length - 1)
newSortOrder =
destinationGroupArray[destinationGroupArray.length - 1].sort_order + 10000;
newSortOrder = destinationGroupArray[destinationGroupArray.length - 1].sort_order + 10000;
else {
if (destination.index > source.index)
newSortOrder =
@ -161,12 +151,10 @@ export const IssuesView: React.FC<Props> = ({
}
} else {
// check if dropping at beginning
if (destination.index === 0)
newSortOrder = destinationGroupArray[0].sort_order - 10000;
if (destination.index === 0) newSortOrder = destinationGroupArray[0].sort_order - 10000;
// check if dropping at last
else if (destination.index === destinationGroupArray.length)
newSortOrder =
destinationGroupArray[destinationGroupArray.length - 1].sort_order + 10000;
newSortOrder = destinationGroupArray[destinationGroupArray.length - 1].sort_order + 10000;
else
newSortOrder =
(destinationGroupArray[destination.index - 1].sort_order +
@ -180,18 +168,14 @@ export const IssuesView: React.FC<Props> = ({
const destinationGroup = destination.droppableId; // destination group id
if (
displayFilters.order_by === "sort_order" ||
source.droppableId !== destination.droppableId
) {
if (displayFilters.order_by === "sort_order" || source.droppableId !== destination.droppableId) {
// different group/column;
// source.droppableId !== destination.droppableId -> even if order by is not sort_order,
// if the issue is moved to a different group, then we will change the group of the
// dragged item(or issue)
if (displayFilters.group_by === "priority")
draggedItem.priority = destinationGroup as TIssuePriorities;
if (displayFilters.group_by === "priority") draggedItem.priority = destinationGroup as TIssuePriorities;
else if (displayFilters.group_by === "state") {
draggedItem.state = destinationGroup;
draggedItem.state_detail = states?.find((s) => s.id === destinationGroup) as IState;
@ -219,14 +203,8 @@ export const IssuesView: React.FC<Props> = ({
return {
...prevData,
[sourceGroup]: orderArrayBy(
sourceGroupArray,
displayFilters.order_by ?? "-created_at"
),
[destinationGroup]: orderArrayBy(
destinationGroupArray,
displayFilters.order_by ?? "-created_at"
),
[sourceGroup]: orderArrayBy(sourceGroupArray, displayFilters.order_by ?? "-created_at"),
[destinationGroup]: orderArrayBy(destinationGroupArray, displayFilters.order_by ?? "-created_at"),
};
},
false
@ -246,14 +224,9 @@ export const IssuesView: React.FC<Props> = ({
user
)
.then((response) => {
const sourceStateBeforeDrag = states?.find(
(state) => state.name === source.droppableId
);
const sourceStateBeforeDrag = states?.find((state) => state.name === source.droppableId);
if (
sourceStateBeforeDrag?.group !== "completed" &&
response?.state_detail?.group === "completed"
)
if (sourceStateBeforeDrag?.group !== "completed" && response?.state_detail?.group === "completed")
trackEventServices.trackIssueMarkedAsDoneEvent(
{
workspaceSlug,
@ -387,12 +360,7 @@ export const IssuesView: React.FC<Props> = ({
);
issuesService
.removeIssueFromCycle(
workspaceSlug as string,
projectId as string,
cycleId as string,
bridgeId
)
.removeIssueFromCycle(workspaceSlug as string, projectId as string, cycleId as string, bridgeId)
.then(() => {
setToastAlert({
title: "Success",
@ -430,12 +398,7 @@ export const IssuesView: React.FC<Props> = ({
);
modulesService
.removeIssueFromModule(
workspaceSlug as string,
projectId as string,
moduleId as string,
bridgeId
)
.removeIssueFromModule(workspaceSlug as string, projectId as string, moduleId as string, bridgeId)
.then(() => {
setToastAlert({
title: "Success",
@ -450,12 +413,9 @@ export const IssuesView: React.FC<Props> = ({
[displayFilters.group_by, workspaceSlug, projectId, moduleId, params, setToastAlert]
);
const nullFilters = Object.keys(filters).filter(
(key) => filters[key as keyof IIssueFilterOptions] === null
);
const nullFilters = Object.keys(filters).filter((key) => filters[key as keyof IIssueFilterOptions] === null);
const areFiltersApplied =
Object.keys(filters).length > 0 && nullFilters.length !== Object.keys(filters).length;
const areFiltersApplied = Object.keys(filters).length > 0 && nullFilters.length !== Object.keys(filters).length;
return (
<>
@ -581,10 +541,7 @@ export const IssuesView: React.FC<Props> = ({
: undefined,
secondaryButton:
cycleId || moduleId ? (
<SecondaryButton
className="flex items-center gap-1.5"
onClick={openIssuesListModal ?? (() => {})}
>
<SecondaryButton className="flex items-center gap-1.5" onClick={openIssuesListModal ?? (() => {})}>
<PlusIcon className="h-4 w-4" />
Add an existing issue
</SecondaryButton>

View File

@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import { mutate } from "swr";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useToast from "hooks/use-toast";
// components
@ -45,12 +45,7 @@ import {
UserAuth,
} from "types";
// fetch-keys
import {
CYCLE_DETAILS,
MODULE_DETAILS,
SUB_ISSUES,
USER_PROFILE_PROJECT_SEGREGATION,
} from "constants/fetch-keys";
import { CYCLE_DETAILS, MODULE_DETAILS, SUB_ISSUES, USER_PROFILE_PROJECT_SEGREGATION } from "constants/fetch-keys";
type Props = {
type?: string;
@ -140,39 +135,24 @@ export const SingleListIssue: React.FC<Props> = ({
);
}
issuesService
.patchIssue(workspaceSlug as string, issue.project, issue.id, formData, user)
.then(() => {
mutateIssues();
issuesService.patchIssue(workspaceSlug as string, issue.project, issue.id, formData, user).then(() => {
mutateIssues();
if (userId)
mutate<IUserProfileProjectSegregation>(
USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString())
);
if (userId)
mutate<IUserProfileProjectSegregation>(
USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString())
);
if (cycleId) mutate(CYCLE_DETAILS(cycleId as string));
if (moduleId) mutate(MODULE_DETAILS(moduleId as string));
});
if (cycleId) mutate(CYCLE_DETAILS(cycleId as string));
if (moduleId) mutate(MODULE_DETAILS(moduleId as string));
});
},
[
displayFilters,
workspaceSlug,
cycleId,
moduleId,
userId,
groupTitle,
index,
mutateIssues,
user,
]
[displayFilters, workspaceSlug, cycleId, moduleId, userId, groupTitle, index, mutateIssues, user]
);
const handleCopyText = () => {
const originURL =
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
copyTextToClipboard(
`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`
).then(() => {
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`).then(() => {
setToastAlert({
type: "success",
title: "Link Copied!",
@ -197,8 +177,7 @@ export const SingleListIssue: React.FC<Props> = ({
});
};
const isNotAllowed =
userAuth.isGuest || userAuth.isViewer || disableUserActions || isArchivedIssues;
const isNotAllowed = userAuth.isGuest || userAuth.isViewer || disableUserActions || isArchivedIssues;
console.log("properties", properties);
@ -243,9 +222,7 @@ export const SingleListIssue: React.FC<Props> = ({
Copy issue link
</ContextMenu.Item>
<a href={issuePath} target="_blank" rel="noreferrer noopener">
<ContextMenu.Item Icon={ArrowTopRightOnSquareIcon}>
Open issue in new tab
</ContextMenu.Item>
<ContextMenu.Item Icon={ArrowTopRightOnSquareIcon}>Open issue in new tab</ContextMenu.Item>
</a>
</>
)}
@ -286,11 +263,7 @@ export const SingleListIssue: React.FC<Props> = ({
</div>
</div>
<div
className={`flex flex-shrink-0 items-center gap-2 text-xs ${
isArchivedIssues ? "opacity-60" : ""
}`}
>
<div className={`flex flex-shrink-0 items-center gap-2 text-xs ${isArchivedIssues ? "opacity-60" : ""}`}>
{properties.priority && (
<ViewPrioritySelect
issue={issue}

View File

@ -5,7 +5,7 @@ import useSWR from "swr";
// headless ui
import { Disclosure, Transition } from "@headlessui/react";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
import projectService from "services/project.service";
// hooks
import useProjects from "hooks/use-projects";
@ -77,9 +77,7 @@ export const SingleList: React.FC<Props> = ({
const { data: issueLabels } = useSWR<IIssueLabels[]>(
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null,
workspaceSlug && projectId
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string)
: null
workspaceSlug && projectId ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) : null
);
const { data: members } = useSWR(
@ -120,12 +118,7 @@ export const SingleList: React.FC<Props> = ({
switch (displayFilters?.group_by) {
case "state":
icon = currentState && (
<StateGroupIcon
stateGroup={currentState.group}
color={currentState.color}
height="16px"
width="16px"
/>
<StateGroupIcon stateGroup={currentState.group} color={currentState.color} height="16px" width="16px" />
);
break;
case "state_detail.group":
@ -152,14 +145,8 @@ export const SingleList: React.FC<Props> = ({
: null);
break;
case "labels":
const labelColor =
issueLabels?.find((label) => label.id === groupTitle)?.color ?? "#000000";
icon = (
<span
className="h-3 w-3 flex-shrink-0 rounded-full"
style={{ backgroundColor: labelColor }}
/>
);
const labelColor = issueLabels?.find((label) => label.id === groupTitle)?.color ?? "#000000";
icon = <span className="h-3 w-3 flex-shrink-0 rounded-full" style={{ backgroundColor: labelColor }} />;
break;
case "assignees":
case "created_by":
@ -181,9 +168,7 @@ export const SingleList: React.FC<Props> = ({
<div className="flex items-center justify-between px-4 py-2.5 bg-custom-background-90">
<Disclosure.Button>
<div className="flex items-center gap-x-3">
{displayFilters?.group_by !== null && (
<div className="flex items-center">{getGroupIcon()}</div>
)}
{displayFilters?.group_by !== null && <div className="flex items-center">{getGroupIcon()}</div>}
{displayFilters?.group_by !== null ? (
<h2
className={`text-sm font-semibold leading-6 text-custom-text-100 ${
@ -226,9 +211,7 @@ export const SingleList: React.FC<Props> = ({
>
<CustomMenu.MenuItem onClick={addIssueToGroup}>Create new</CustomMenu.MenuItem>
{openIssuesListModal && (
<CustomMenu.MenuItem onClick={openIssuesListModal}>
Add an existing issue
</CustomMenu.MenuItem>
<CustomMenu.MenuItem onClick={openIssuesListModal}>Add an existing issue</CustomMenu.MenuItem>
)}
</CustomMenu>
)}
@ -256,19 +239,14 @@ export const SingleList: React.FC<Props> = ({
makeIssueCopy={() => handleIssueAction(issue, "copy")}
handleDeleteIssue={() => handleIssueAction(issue, "delete")}
handleDraftIssueSelect={
handleDraftIssueAction
? () => handleDraftIssueAction(issue, "edit")
: undefined
handleDraftIssueAction ? () => handleDraftIssueAction(issue, "edit") : undefined
}
handleDraftIssueDelete={
handleDraftIssueAction
? () => handleDraftIssueAction(issue, "delete")
: undefined
handleDraftIssueAction ? () => handleDraftIssueAction(issue, "delete") : undefined
}
handleMyIssueOpen={handleMyIssueOpen}
removeIssue={() => {
if (removeIssue !== null && issue.bridge_id)
removeIssue(issue.bridge_id, issue.id);
if (removeIssue !== null && issue.bridge_id) removeIssue(issue.bridge_id, issue.id);
}}
disableUserActions={disableUserActions}
user={user}
@ -277,9 +255,7 @@ export const SingleList: React.FC<Props> = ({
/>
))
) : (
<p className="bg-custom-background-100 px-4 py-2.5 text-sm text-custom-text-200">
No issues.
</p>
<p className="bg-custom-background-100 px-4 py-2.5 text-sm text-custom-text-200">No issues.</p>
)
) : (
<div className="flex h-full w-full items-center justify-center">Loading...</div>

View File

@ -17,17 +17,12 @@ import {
import { Popover2 } from "@blueprintjs/popover2";
// icons
import { Icon } from "components/ui";
import {
EllipsisHorizontalIcon,
LinkIcon,
PencilIcon,
TrashIcon,
} from "@heroicons/react/24/outline";
import { EllipsisHorizontalIcon, LinkIcon, PencilIcon, TrashIcon } from "@heroicons/react/24/outline";
// hooks
import useSpreadsheetIssuesView from "hooks/use-spreadsheet-issues-view";
import useToast from "hooks/use-toast";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// constant
import {
CYCLE_DETAILS,
@ -133,13 +128,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
);
issuesService
.patchIssue(
workspaceSlug as string,
projectId as string,
issue.id as string,
formData,
user
)
.patchIssue(workspaceSlug as string, projectId as string, issue.id as string, formData, user)
.then(() => {
if (issue.parent) {
mutate(SUB_ISSUES(issue.parent as string));
@ -167,11 +156,8 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
};
const handleCopyText = () => {
const originURL =
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
copyTextToClipboard(
`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`
).then(() => {
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`).then(() => {
setToastAlert({
type: "success",
title: "Link Copied!",

View File

@ -9,7 +9,7 @@ import { useForm } from "react-hook-form";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// services
import estimatesService from "services/estimates.service";
import estimatesService from "services/project_estimates.service";
// hooks
import useToast from "hooks/use-toast";
// ui
@ -119,13 +119,7 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
);
await estimatesService
.patchEstimate(
workspaceSlug as string,
projectId as string,
data?.id as string,
payload,
user
)
.patchEstimate(workspaceSlug as string, projectId as string, data?.id as string, payload, user)
.then(() => {
mutate(ESTIMATES_LIST(projectId.toString()));
mutate(ESTIMATE_DETAILS(data.id));
@ -257,9 +251,7 @@ export const CreateUpdateEstimateModal: React.FC<Props> = ({ handleClose, data,
<Dialog.Panel className="relative transform rounded-lg border border-custom-border-200 bg-custom-background-100 px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
<form onSubmit={handleSubmit(onSubmit)}>
<div className="space-y-3">
<div className="text-lg font-medium leading-6">
{data ? "Update" : "Create"} Estimate
</div>
<div className="text-lg font-medium leading-6">{data ? "Update" : "Create"} Estimate</div>
<div>
<Input
id="name"

View File

@ -1,10 +1,9 @@
import React, { useState } from "react";
import { useRouter } from "next/router";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// services
import CSVIntegrationService from "services/integration/csv.services";
import CSVIntegrationService from "services/csv.services";
// hooks
import useToast from "hooks/use-toast";
// ui
@ -23,13 +22,9 @@ type Props = {
mutateServices: () => void;
};
export const Exporter: React.FC<Props> = ({
isOpen,
handleClose,
user,
provider,
mutateServices,
}) => {
const cvsService = new CSVIntegrationService();
export const Exporter: React.FC<Props> = ({ isOpen, handleClose, user, provider, mutateServices }) => {
const [exportLoading, setExportLoading] = useState(false);
const router = useRouter();
const { workspaceSlug } = router.query;
@ -60,7 +55,8 @@ export const Exporter: React.FC<Props> = ({
project: value,
multiple: multiple,
};
await CSVIntegrationService.exportCSVService(workspaceSlug as string, payload, user)
await cvsService
.exportCSVService(workspaceSlug as string, payload, user)
.then(() => {
mutateServices();
router.push(`/${workspaceSlug}/settings/exports`);
@ -69,13 +65,7 @@ export const Exporter: React.FC<Props> = ({
type: "success",
title: "Export Successful",
message: `You will be able to download the exported ${
provider === "csv"
? "CSV"
: provider === "xlsx"
? "Excel"
: provider === "json"
? "JSON"
: ""
provider === "csv" ? "CSV" : provider === "xlsx" ? "Excel" : provider === "json" ? "JSON" : ""
} from the previous export.`,
});
})
@ -122,13 +112,7 @@ export const Exporter: React.FC<Props> = ({
<span className="flex items-center justify-start">
<h3 className="text-xl font-medium 2xl:text-2xl">
Export to{" "}
{provider === "csv"
? "CSV"
: provider === "xlsx"
? "Excel"
: provider === "json"
? "JSON"
: ""}
{provider === "csv" ? "CSV" : provider === "xlsx" ? "Excel" : provider === "json" ? "JSON" : ""}
</h3>
</span>
</div>
@ -155,22 +139,12 @@ export const Exporter: React.FC<Props> = ({
onClick={() => setMultiple(!multiple)}
className="flex items-center gap-2 max-w-min cursor-pointer"
>
<input
type="checkbox"
checked={multiple}
onChange={() => setMultiple(!multiple)}
/>
<div className="text-sm whitespace-nowrap">
Export the data into separate files
</div>
<input type="checkbox" checked={multiple} onChange={() => setMultiple(!multiple)} />
<div className="text-sm whitespace-nowrap">Export the data into separate files</div>
</div>
<div className="flex justify-end gap-2">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton
onClick={ExportCSVToMail}
disabled={exportLoading}
loading={exportLoading}
>
<PrimaryButton onClick={ExportCSVToMail} disabled={exportLoading} loading={exportLoading}>
{exportLoading ? "Exporting..." : "Export"}
</PrimaryButton>
</div>

View File

@ -9,7 +9,7 @@ import useSWR, { mutate } from "swr";
// hooks
import useUserAuth from "hooks/use-user-auth";
// services
import IntegrationService from "services/integration";
import IntegrationService from "services/integration.service";
// components
import { Exporter, SingleExport } from "components/exporter";
// ui
@ -32,9 +32,7 @@ const IntegrationGuide = () => {
const { user } = useUserAuth();
const { data: exporterServices } = useSWR(
workspaceSlug && cursor
? EXPORT_SERVICES_LIST(workspaceSlug as string, cursor, `${per_page}`)
: null,
workspaceSlug && cursor ? EXPORT_SERVICES_LIST(workspaceSlug as string, cursor, `${per_page}`) : null,
workspaceSlug && cursor
? () => IntegrationService.getExportsServicesList(workspaceSlug as string, cursor, per_page)
: null
@ -57,20 +55,11 @@ const IntegrationGuide = () => {
<div className="flex items-start justify-between gap-4 w-full">
<div className="flex item-center gap-2.5">
<div className="relative h-10 w-10 flex-shrink-0">
<Image
src={service.logo}
layout="fill"
objectFit="cover"
alt={`${service.title} Logo`}
/>
<Image src={service.logo} layout="fill" objectFit="cover" alt={`${service.title} Logo`} />
</div>
<div>
<h3 className="flex items-center gap-4 text-sm font-medium">
{service.title}
</h3>
<p className="text-sm text-custom-text-200 tracking-tight">
{service.description}
</p>
<h3 className="flex items-center gap-4 text-sm font-medium">{service.title}</h3>
<p className="text-sm text-custom-text-200 tracking-tight">{service.description}</p>
</div>
</div>
<div className="flex-shrink-0">
@ -96,9 +85,9 @@ const IntegrationGuide = () => {
className="flex flex-shrink-0 items-center gap-1 rounded bg-custom-background-80 py-1 px-1.5 text-xs outline-none"
onClick={() => {
setRefreshing(true);
mutate(
EXPORT_SERVICES_LIST(workspaceSlug as string, `${cursor}`, `${per_page}`)
).then(() => setRefreshing(false));
mutate(EXPORT_SERVICES_LIST(workspaceSlug as string, `${cursor}`, `${per_page}`)).then(() =>
setRefreshing(false)
);
}}
>
<ArrowPathIcon className={`h-3 w-3 ${refreshing ? "animate-spin" : ""}`} />{" "}
@ -108,9 +97,7 @@ const IntegrationGuide = () => {
<div className="flex gap-2 items-center text-xs">
<button
disabled={!exporterServices?.prev_page_results}
onClick={() =>
exporterServices?.prev_page_results && setCursor(exporterServices?.prev_cursor)
}
onClick={() => exporterServices?.prev_page_results && setCursor(exporterServices?.prev_cursor)}
className={`flex items-center border border-custom-primary-100 text-custom-primary-100 px-1 rounded ${
exporterServices?.prev_page_results
? "cursor-pointer hover:bg-custom-primary-100 hover:text-white"
@ -122,9 +109,7 @@ const IntegrationGuide = () => {
</button>
<button
disabled={!exporterServices?.next_page_results}
onClick={() =>
exporterServices?.next_page_results && setCursor(exporterServices?.next_cursor)
}
onClick={() => exporterServices?.next_page_results && setCursor(exporterServices?.next_cursor)}
className={`flex items-center border border-custom-primary-100 text-custom-primary-100 px-1 rounded ${
exporterServices?.next_page_results
? "cursor-pointer hover:bg-custom-primary-100 hover:text-white"
@ -147,9 +132,7 @@ const IntegrationGuide = () => {
</div>
</div>
) : (
<p className="text-sm text-custom-text-200 px-4 py-6">
No previous export available.
</p>
<p className="text-sm text-custom-text-200 px-4 py-6">No previous export available.</p>
)
) : (
<Loader className="mt-6 grid grid-cols-1 gap-3">
@ -169,9 +152,7 @@ const IntegrationGuide = () => {
data={null}
user={user}
provider={provider}
mutateServices={() =>
mutate(EXPORT_SERVICES_LIST(workspaceSlug as string, `${cursor}`, `${per_page}`))
}
mutateServices={() => mutate(EXPORT_SERVICES_LIST(workspaceSlug as string, `${cursor}`, `${per_page}`))}
/>
)}
</div>

View File

@ -1,7 +1,7 @@
import { KeyedMutator } from "swr";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// types
import { ICurrentUserResponse, IIssue } from "types";
import { IBlockUpdateData } from "../types";
@ -34,8 +34,7 @@ export const updateGanttIssue = (
const newPayload: any = { ...payload };
if (newPayload.sort_order && payload.sort_order)
newPayload.sort_order = payload.sort_order.newSortOrder;
if (newPayload.sort_order && payload.sort_order) newPayload.sort_order = payload.sort_order.newSortOrder;
issuesService.patchIssue(workspaceSlug, issue.project, issue.id, newPayload, user);
};

View File

@ -5,7 +5,7 @@ import useSWR, { mutate } from "swr";
// components
import { AddComment, IssueActivitySection } from "components/issues";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useUser from "hooks/use-user";
import useToast from "hooks/use-toast";
@ -25,16 +25,9 @@ export const InboxIssueActivity: React.FC<Props> = ({ issueDetails }) => {
const { user } = useUser();
const { data: issueActivity, mutate: mutateIssueActivity } = useSWR(
workspaceSlug && projectId && inboxIssueId ? PROJECT_ISSUES_ACTIVITY(inboxIssueId.toString()) : null,
workspaceSlug && projectId && inboxIssueId
? PROJECT_ISSUES_ACTIVITY(inboxIssueId.toString())
: null,
workspaceSlug && projectId && inboxIssueId
? () =>
issuesService.getIssueActivities(
workspaceSlug.toString(),
projectId.toString(),
inboxIssueId.toString()
)
? () => issuesService.getIssueActivities(workspaceSlug.toString(), projectId.toString(), inboxIssueId.toString())
: null
);
@ -42,14 +35,7 @@ export const InboxIssueActivity: React.FC<Props> = ({ issueDetails }) => {
if (!workspaceSlug || !projectId || !inboxIssueId) return;
await issuesService
.patchIssueComment(
workspaceSlug as string,
projectId as string,
inboxIssueId as string,
commentId,
data,
user
)
.patchIssueComment(workspaceSlug as string, projectId as string, inboxIssueId as string, commentId, data, user)
.then(() => mutateIssueActivity());
};
@ -59,13 +45,7 @@ export const InboxIssueActivity: React.FC<Props> = ({ issueDetails }) => {
mutateIssueActivity((prevData: any) => prevData?.filter((p: any) => p.id !== commentId), false);
await issuesService
.deleteIssueComment(
workspaceSlug as string,
projectId as string,
inboxIssueId as string,
commentId,
user
)
.deleteIssueComment(workspaceSlug as string, projectId as string, inboxIssueId as string, commentId, user)
.then(() => mutateIssueActivity());
};
@ -73,13 +53,7 @@ export const InboxIssueActivity: React.FC<Props> = ({ issueDetails }) => {
if (!workspaceSlug || !issueDetails) return;
await issuesService
.createIssueComment(
workspaceSlug.toString(),
issueDetails.project,
issueDetails.id,
formData,
user
)
.createIssueComment(workspaceSlug.toString(), issueDetails.project, issueDetails.id, formData, user)
.then(() => {
mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id));
})

View File

@ -11,7 +11,7 @@ import { Combobox, Dialog, Transition } from "@headlessui/react";
// hooks
import useToast from "hooks/use-toast";
// services
import issuesServices from "services/issues.service";
import issuesServices from "services/issue.service";
// ui
import { PrimaryButton, SecondaryButton } from "components/ui";
// icons
@ -39,9 +39,7 @@ export const SelectDuplicateInboxIssueModal: React.FC<Props> = (props) => {
const { workspaceSlug, projectId, issueId } = router.query;
const { data: issues } = useSWR(
workspaceSlug && projectId
? PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)
: null,
workspaceSlug && projectId ? PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string) : null,
workspaceSlug && projectId
? () =>
issuesServices
@ -71,8 +69,7 @@ export const SelectDuplicateInboxIssueModal: React.FC<Props> = (props) => {
handleClose();
};
const filteredIssues =
(query === "" ? issues : issues?.filter((issue) => issue.name.includes(query))) ?? [];
const filteredIssues = (query === "" ? issues : issues?.filter((issue) => issue.name.includes(query))) ?? [];
return (
<Transition.Root show={isOpen} as={React.Fragment} afterLeave={() => setQuery("")} appear>
@ -128,9 +125,7 @@ export const SelectDuplicateInboxIssueModal: React.FC<Props> = (props) => {
{filteredIssues.length > 0 ? (
<li className="p-2">
{query === "" && (
<h2 className="mt-4 mb-2 px-3 text-xs font-semibold text-custom-text-100">
Select issue
</h2>
<h2 className="mt-4 mb-2 px-3 text-xs font-semibold text-custom-text-100">Select issue</h2>
)}
<ul className="text-sm text-custom-text-100">
{filteredIssues.map((issue) => (
@ -140,9 +135,7 @@ export const SelectDuplicateInboxIssueModal: React.FC<Props> = (props) => {
value={issue.id}
className={({ active, selected }) =>
`flex w-full cursor-pointer select-none items-center gap-2 rounded-md px-3 py-2 text-custom-text-200 ${
active || selected
? "bg-custom-background-80 text-custom-text-100"
: ""
active || selected ? "bg-custom-background-80 text-custom-text-100" : ""
} `
}
>
@ -154,11 +147,8 @@ export const SelectDuplicateInboxIssueModal: React.FC<Props> = (props) => {
}}
/>
<span className="flex-shrink-0 text-xs text-custom-text-200">
{
issues?.find((i) => i.id === issue.id)?.project_detail
?.identifier
}
-{issue.sequence_id}
{issues?.find((i) => i.id === issue.id)?.project_detail?.identifier}-
{issue.sequence_id}
</span>
<span className="text-custom-text-200">{issue.name}</span>
</div>
@ -171,10 +161,7 @@ export const SelectDuplicateInboxIssueModal: React.FC<Props> = (props) => {
<LayerDiagonalIcon height="56" width="56" />
<h3 className="text-sm text-custom-text-200">
No issues found. Create a new issue with{" "}
<pre className="inline rounded bg-custom-background-80 px-2 py-1">
C
</pre>
.
<pre className="inline rounded bg-custom-background-80 px-2 py-1">C</pre>.
</h3>
</div>
)}

View File

@ -7,7 +7,7 @@ import { mutate } from "swr";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// services
import IntegrationService from "services/integration";
import IntegrationService from "services/integration.service";
// hooks
import useToast from "hooks/use-toast";
// ui
@ -92,10 +92,7 @@ export const DeleteImportModal: React.FC<Props> = ({ isOpen, handleClose, data,
<div className="flex flex-col gap-6 p-6">
<div className="flex w-full items-center justify-start gap-6">
<span className="place-items-center rounded-full bg-red-500/20 p-4">
<ExclamationTriangleIcon
className="h-6 w-6 text-red-500"
aria-hidden="true"
/>
<ExclamationTriangleIcon className="h-6 w-6 text-red-500" aria-hidden="true" />
</span>
<span className="flex items-center justify-start">
<h3 className="text-xl font-medium 2xl:text-2xl">Delete Project</h3>
@ -104,17 +101,13 @@ export const DeleteImportModal: React.FC<Props> = ({ isOpen, handleClose, data,
<span>
<p className="text-sm leading-7 text-custom-text-200">
Are you sure you want to delete import from{" "}
<span className="break-words font-semibold capitalize text-custom-text-100">
{data?.service}
</span>
? All of the data related to the import will be permanently removed. This
action cannot be undone.
<span className="break-words font-semibold capitalize text-custom-text-100">{data?.service}</span>
? All of the data related to the import will be permanently removed. This action cannot be undone.
</p>
</span>
<div>
<p className="text-sm text-custom-text-200">
To confirm, type{" "}
<span className="font-medium text-custom-text-100">delete import</span> below:
To confirm, type <span className="font-medium text-custom-text-100">delete import</span> below:
</p>
<Input
type="text"
@ -129,11 +122,7 @@ export const DeleteImportModal: React.FC<Props> = ({ isOpen, handleClose, data,
</div>
<div className="flex justify-end gap-2">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<DangerButton
onClick={handleDeletion}
disabled={!confirmDeleteImport}
loading={deleteLoading}
>
<DangerButton onClick={handleDeletion} disabled={!confirmDeleteImport} loading={deleteLoading}>
{deleteLoading ? "Deleting..." : "Delete Project"}
</DangerButton>
</div>

View File

@ -7,7 +7,7 @@ import useSWR from "swr";
// react-hook-form
import { UseFormSetValue } from "react-hook-form";
// services
import GithubIntegrationService from "services/integration/github.service";
import GithubIntegrationService from "services/github.service";
// ui
import { Loader, PrimaryButton, SecondaryButton } from "components/ui";
// types
@ -22,19 +22,12 @@ type Props = {
setValue: UseFormSetValue<TFormValues>;
};
export const GithubRepoDetails: FC<Props> = ({
selectedRepo,
handleStepChange,
setUsers,
setValue,
}) => {
export const GithubRepoDetails: FC<Props> = ({ selectedRepo, handleStepChange, setUsers, setValue }) => {
const router = useRouter();
const { workspaceSlug } = router.query;
const { data: repoInfo } = useSWR(
workspaceSlug && selectedRepo
? GITHUB_REPOSITORY_INFO(workspaceSlug as string, selectedRepo.name)
: null,
workspaceSlug && selectedRepo ? GITHUB_REPOSITORY_INFO(workspaceSlug as string, selectedRepo.name) : null,
workspaceSlug && selectedRepo
? () =>
GithubIntegrationService.getGithubRepoInfo(workspaceSlug as string, {

View File

@ -9,8 +9,8 @@ import useSWR, { mutate } from "swr";
// react-hook-form
import { useForm } from "react-hook-form";
// services
import IntegrationService from "services/integration";
import GithubIntegrationService from "services/integration/github.service";
import IntegrationService from "services/integration.service";
import GithubIntegrationService from "services/github.service";
// hooks
import useToast from "hooks/use-toast";
// components
@ -29,18 +29,9 @@ import GithubLogo from "public/services/github.png";
// types
import { ICurrentUserResponse, IGithubRepoCollaborator, IGithubServiceImportFormData } from "types";
// fetch-keys
import {
APP_INTEGRATIONS,
IMPORTER_SERVICES_LIST,
WORKSPACE_INTEGRATIONS,
} from "constants/fetch-keys";
import { APP_INTEGRATIONS, IMPORTER_SERVICES_LIST, WORKSPACE_INTEGRATIONS } from "constants/fetch-keys";
export type TIntegrationSteps =
| "import-configure"
| "import-data"
| "repo-details"
| "import-users"
| "import-confirm";
export type TIntegrationSteps = "import-configure" | "import-data" | "repo-details" | "import-users" | "import-confirm";
export interface IIntegrationData {
state: TIntegrationSteps;
}
@ -108,21 +99,15 @@ export const GithubImporterRoot: React.FC<Props> = ({ user }) => {
defaultValues: defaultFormValues,
});
const { data: appIntegrations } = useSWR(APP_INTEGRATIONS, () =>
IntegrationService.getAppIntegrationsList()
);
const { data: appIntegrations } = useSWR(APP_INTEGRATIONS, () => IntegrationService.getAppIntegrationsList());
const { data: workspaceIntegrations } = useSWR(
workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug as string) : null,
workspaceSlug
? () => IntegrationService.getWorkspaceIntegrationsList(workspaceSlug as string)
: null
workspaceSlug ? () => IntegrationService.getWorkspaceIntegrationsList(workspaceSlug as string) : null
);
const activeIntegrationState = () => {
const currentElementIndex = integrationWorkflowData.findIndex(
(i) => i?.key === currentStep?.state
);
const currentElementIndex = integrationWorkflowData.findIndex((i) => i?.key === currentStep?.state);
return currentElementIndex;
};
@ -133,14 +118,11 @@ export const GithubImporterRoot: React.FC<Props> = ({ user }) => {
// current integration from all the integrations available
const integration =
appIntegrations &&
appIntegrations.length > 0 &&
appIntegrations.find((i) => i.provider === provider);
appIntegrations && appIntegrations.length > 0 && appIntegrations.find((i) => i.provider === provider);
// current integration from workspace integrations
const workspaceIntegration =
integration &&
workspaceIntegrations?.find((i: any) => i.integration_detail.id === integration.id);
integration && workspaceIntegrations?.find((i: any) => i.integration_detail.id === integration.id);
const createGithubImporterService = async (formData: TFormValues) => {
if (!formData.github || !formData.project) return;
@ -214,9 +196,7 @@ export const GithubImporterRoot: React.FC<Props> = ({ user }) => {
<div
key={index}
className={`border-b px-7 ${
index <= activeIntegrationState() - 1
? `border-custom-primary`
: `border-custom-border-200`
index <= activeIntegrationState() - 1 ? `border-custom-primary` : `border-custom-border-200`
}`}
>
{" "}

View File

@ -9,14 +9,9 @@ import useSWR, { mutate } from "swr";
// hooks
import useUserAuth from "hooks/use-user-auth";
// services
import IntegrationService from "services/integration";
import IntegrationService from "services/integration.service";
// components
import {
DeleteImportModal,
GithubImporterRoot,
JiraImporterRoot,
SingleImport,
} from "components/integration";
import { DeleteImportModal, GithubImporterRoot, JiraImporterRoot, SingleImport } from "components/integration";
// ui
import { Loader, PrimaryButton } from "components/ui";
// icons
@ -85,18 +80,11 @@ const IntegrationGuide = () => {
>
<div className="flex items-start gap-4">
<div className="relative h-10 w-10 flex-shrink-0">
<Image
src={service.logo}
layout="fill"
objectFit="cover"
alt={`${service.title} Logo`}
/>
<Image src={service.logo} layout="fill" objectFit="cover" alt={`${service.title} Logo`} />
</div>
<div>
<h3 className="flex items-center gap-4 text-sm font-medium">{service.title}</h3>
<p className="text-sm text-custom-text-200 tracking-tight">
{service.description}
</p>
<p className="text-sm text-custom-text-200 tracking-tight">{service.description}</p>
</div>
</div>
<div className="flex-shrink-0">
@ -119,9 +107,7 @@ const IntegrationGuide = () => {
className="flex flex-shrink-0 items-center gap-1 rounded bg-custom-background-80 py-1 px-1.5 text-xs outline-none"
onClick={() => {
setRefreshing(true);
mutate(IMPORTER_SERVICES_LIST(workspaceSlug as string)).then(() =>
setRefreshing(false)
);
mutate(IMPORTER_SERVICES_LIST(workspaceSlug as string)).then(() => setRefreshing(false));
}}
>
<ArrowPathIcon className={`h-3 w-3 ${refreshing ? "animate-spin" : ""}`} />{" "}
@ -145,9 +131,7 @@ const IntegrationGuide = () => {
</div>
</div>
) : (
<p className="text-sm text-custom-text-200 px-4 py-6">
No previous imports available.
</p>
<p className="text-sm text-custom-text-200 px-4 py-6">No previous imports available.</p>
)
) : (
<Loader className="mt-6 grid grid-cols-1 gap-3">

View File

@ -10,7 +10,7 @@ import useSWR from "swr";
import { useFormContext, Controller } from "react-hook-form";
// services
import jiraImporterService from "services/integration/jira.service";
import jiraImporterService from "services/jira.service";
// fetch keys
import { JIRA_IMPORTER_DETAIL } from "constants/fetch-keys";
@ -157,9 +157,7 @@ export const JiraProjectDetail: React.FC<Props> = (props) => {
<Controller
control={control}
name="config.epics_to_modules"
render={({ field: { value, onChange } }) => (
<ToggleSwitch onChange={onChange} value={value} />
)}
render={({ field: { value, onChange } }) => <ToggleSwitch onChange={onChange} value={value} />}
/>
</div>
</div>

View File

@ -16,7 +16,7 @@ import { ArrowLeftIcon, ListBulletIcon } from "@heroicons/react/24/outline";
import { CogIcon, UsersIcon, CheckIcon } from "components/icons";
// services
import jiraImporterService from "services/integration/jira.service";
import jiraImporterService from "services/jira.service";
// fetch keys
import { IMPORTER_SERVICES_LIST } from "constants/fetch-keys";
@ -100,9 +100,7 @@ export const JiraImporterRoot: React.FC<Props> = ({ user }) => {
};
const activeIntegrationState = () => {
const currentElementIndex = integrationWorkflowData.findIndex(
(i) => i?.key === currentStep?.state
);
const currentElementIndex = integrationWorkflowData.findIndex((i) => i?.key === currentStep?.state);
return currentElementIndex;
};
@ -155,9 +153,7 @@ export const JiraImporterRoot: React.FC<Props> = ({ user }) => {
<div
key={index}
className={`border-b px-7 ${
index <= activeIntegrationState() - 1
? `border-custom-primary`
: `border-custom-border-200`
index <= activeIntegrationState() - 1 ? `border-custom-primary` : `border-custom-border-200`
}`}
>
{" "}
@ -174,10 +170,7 @@ export const JiraImporterRoot: React.FC<Props> = ({ user }) => {
<div className="h-full w-full overflow-y-auto">
{currentStep.state === "import-configure" && <JiraGetImportDetail />}
{currentStep.state === "display-import-data" && (
<JiraProjectDetail
setDisableTopBarAfter={setDisableTopBarAfter}
setCurrentStep={setCurrentStep}
/>
<JiraProjectDetail setDisableTopBarAfter={setDisableTopBarAfter} setCurrentStep={setCurrentStep} />
)}
{currentStep?.state === "import-users" && <JiraImportUsers />}
{currentStep?.state === "import-confirmation" && <JiraConfirmImport />}
@ -199,15 +192,9 @@ export const JiraImporterRoot: React.FC<Props> = ({ user }) => {
</SecondaryButton>
)}
<PrimaryButton
disabled={
disableTopBarAfter === currentStep?.state ||
!isValid ||
methods.formState.isSubmitting
}
disabled={disableTopBarAfter === currentStep?.state || !isValid || methods.formState.isSubmitting}
onClick={() => {
const currentElementIndex = integrationWorkflowData.findIndex(
(i) => i?.key === currentStep?.state
);
const currentElementIndex = integrationWorkflowData.findIndex((i) => i?.key === currentStep?.state);
if (currentElementIndex === integrationWorkflowData.length - 1) {
methods.handleSubmit(onSubmit)();

View File

@ -6,7 +6,7 @@ import { useRouter } from "next/router";
import useSWR, { mutate } from "swr";
// services
import IntegrationService from "services/integration";
import IntegrationService from "services/integration.service";
// hooks
import useToast from "hooks/use-toast";
import useIntegrationPopup from "hooks/use-integration-popup";
@ -50,25 +50,17 @@ export const SingleIntegrationCard: React.FC<Props> = ({ integration }) => {
const { data: workspaceIntegrations } = useSWR(
workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug as string) : null,
() =>
workspaceSlug
? IntegrationService.getWorkspaceIntegrationsList(workspaceSlug as string)
: null
() => (workspaceSlug ? IntegrationService.getWorkspaceIntegrationsList(workspaceSlug as string) : null)
);
const handleRemoveIntegration = async () => {
if (!workspaceSlug || !integration || !workspaceIntegrations) return;
const workspaceIntegrationId = workspaceIntegrations?.find(
(i) => i.integration === integration.id
)?.id;
const workspaceIntegrationId = workspaceIntegrations?.find((i) => i.integration === integration.id)?.id;
setDeletingIntegration(true);
await IntegrationService.deleteWorkspaceIntegration(
workspaceSlug as string,
workspaceIntegrationId ?? ""
)
await IntegrationService.deleteWorkspaceIntegration(workspaceSlug as string, workspaceIntegrationId ?? "")
.then(() => {
mutate<IWorkspaceIntegration[]>(
WORKSPACE_INTEGRATIONS(workspaceSlug as string),
@ -94,18 +86,13 @@ export const SingleIntegrationCard: React.FC<Props> = ({ integration }) => {
});
};
const isInstalled = workspaceIntegrations?.find(
(i: any) => i.integration_detail.id === integration.id
);
const isInstalled = workspaceIntegrations?.find((i: any) => i.integration_detail.id === integration.id);
return (
<div className="flex items-center justify-between gap-2 border-b border-custom-border-200 bg-custom-background-100 px-4 py-6">
<div className="flex items-start gap-4">
<div className="h-10 w-10 flex-shrink-0">
<Image
src={integrationDetails[integration.provider].logo}
alt={`${integration.title} Logo`}
/>
<Image src={integrationDetails[integration.provider].logo} alt={`${integration.title} Logo`} />
</div>
<div>
<h3 className="flex items-center gap-2 text-sm font-medium">

View File

@ -4,7 +4,7 @@ import { useRouter } from "next/router";
import useSWR, { mutate } from "swr";
// services
import appinstallationsService from "services/app-installations.service";
import appinstallationsService from "services/app_installation.service";
// ui
import { Loader } from "components/ui";
// hooks
@ -20,8 +20,7 @@ type Props = {
};
export const SelectChannel: React.FC<Props> = ({ integration }) => {
const [slackChannelAvailabilityToggle, setSlackChannelAvailabilityToggle] =
useState<boolean>(false);
const [slackChannelAvailabilityToggle, setSlackChannelAvailabilityToggle] = useState<boolean>(false);
const [slackChannel, setSlackChannel] = useState<ISlackIntegration | null>(null);
const router = useRouter();
@ -65,12 +64,7 @@ export const SelectChannel: React.FC<Props> = ({ integration }) => {
setSlackChannel(null);
});
appinstallationsService
.removeSlackChannel(
workspaceSlug as string,
projectId as string,
integration.id as string,
slackChannel?.id
)
.removeSlackChannel(workspaceSlug as string, projectId as string, integration.id as string, slackChannel?.id)
.catch((err) => console.log(err));
};

View File

@ -7,7 +7,7 @@ import { observer } from "mobx-react-lite";
import { RootStore } from "store/root";
import { useMobxStore } from "lib/mobx/store-provider";
// types and default data
import { TIssueLayouts } from "store/issue-filters";
import { TIssueLayouts } from "store/issue_filters.legacy";
import { issueFilterVisibilityData } from "store/helpers/issue-data";
export const LayoutSelection = observer(() => {

View File

@ -7,7 +7,7 @@ import { mutate } from "swr";
// react-dropzone
import { useDropzone } from "react-dropzone";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useToast from "hooks/use-toast";
// types
@ -44,12 +44,7 @@ export const IssueAttachmentUpload: React.FC<Props> = ({ disabled = false }) =>
setIsLoading(true);
issuesService
.uploadIssueAttachment(
workspaceSlug as string,
projectId as string,
issueId as string,
formData
)
.uploadIssueAttachment(workspaceSlug as string, projectId as string, issueId as string, formData)
.then((res) => {
mutate<IIssueAttachment[]>(
ISSUE_ATTACHMENTS(issueId as string),
@ -83,9 +78,7 @@ export const IssueAttachmentUpload: React.FC<Props> = ({ disabled = false }) =>
});
const fileError =
fileRejections.length > 0
? `Invalid file type or size (max ${maxFileSize / 1024 / 1024} MB)`
: null;
fileRejections.length > 0 ? `Invalid file type or size (max ${maxFileSize / 1024 / 1024} MB)` : null;
return (
<div

View File

@ -12,7 +12,7 @@ import { DeleteAttachmentModal } from "./delete-attachment-modal";
import { XMarkIcon } from "@heroicons/react/24/outline";
import { ExclamationIcon, getFileIcon } from "components/icons";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
import projectService from "services/project.service";
// fetch-key
import { ISSUE_ATTACHMENTS, PROJECT_MEMBERS } from "constants/fetch-keys";
@ -33,12 +33,7 @@ export const IssueAttachments = () => {
const { data: attachments } = useSWR<IIssueAttachment[]>(
workspaceSlug && projectId && issueId ? ISSUE_ATTACHMENTS(issueId as string) : null,
workspaceSlug && projectId && issueId
? () =>
issuesService.getIssueAttachment(
workspaceSlug as string,
projectId as string,
issueId as string
)
? () => issuesService.getIssueAttachment(workspaceSlug as string, projectId as string, issueId as string)
: null
);
@ -70,14 +65,11 @@ export const IssueAttachments = () => {
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
<Tooltip tooltipContent={getFileName(file.attributes.name)}>
<span className="text-sm">
{truncateText(`${getFileName(file.attributes.name)}`, 10)}
</span>
<span className="text-sm">{truncateText(`${getFileName(file.attributes.name)}`, 10)}</span>
</Tooltip>
<Tooltip
tooltipContent={`${
people?.find((person) => person.member.id === file.updated_by)?.member
.display_name ?? ""
people?.find((person) => person.member.id === file.updated_by)?.member.display_name ?? ""
} uploaded on ${renderLongDateFormat(file.updated_at)}`}
>
<span>

View File

@ -7,7 +7,7 @@ import { mutate } from "swr";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useToast from "hooks/use-toast";
// ui
@ -47,12 +47,7 @@ export const DeleteAttachmentModal: React.FC<Props> = ({ isOpen, setIsOpen, data
);
await issuesService
.deleteIssueAttachment(
workspaceSlug as string,
projectId as string,
issueId as string,
assetId as string
)
.deleteIssueAttachment(workspaceSlug as string, projectId as string, issueId as string, assetId as string)
.then(() => mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)))
.catch(() => {
setToastAlert({
@ -94,24 +89,17 @@ export const DeleteAttachmentModal: React.FC<Props> = ({ isOpen, setIsOpen, data
<div className="bg-custom-background-80 px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
<ExclamationTriangleIcon
className="h-6 w-6 text-red-600"
aria-hidden="true"
/>
<ExclamationTriangleIcon className="h-6 w-6 text-red-600" aria-hidden="true" />
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-custom-text-100"
>
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-custom-text-100">
Delete Attachment
</Dialog.Title>
<div className="mt-2">
<p className="text-sm text-custom-text-200">
Are you sure you want to delete attachment-{" "}
<span className="font-bold">{getFileName(data.attributes.name)}</span>?
This attachment will be permanently removed. This action cannot be
undone.
<span className="font-bold">{getFileName(data.attributes.name)}</span>? This attachment will
be permanently removed. This action cannot be undone.
</p>
</div>
</div>

View File

@ -7,7 +7,7 @@ import { mutate } from "swr";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// services
import issueServices from "services/issues.service";
import issueServices from "services/issue.service";
// hooks
import useIssuesView from "hooks/use-issues-view";
import useToast from "hooks/use-toast";
@ -109,10 +109,7 @@ export const DeleteDraftIssueModal: React.FC<Props> = (props) => {
<div className="flex flex-col gap-6 p-6">
<div className="flex w-full items-center justify-start gap-6">
<span className="place-items-center rounded-full bg-red-500/20 p-4">
<ExclamationTriangleIcon
className="h-6 w-6 text-red-600"
aria-hidden="true"
/>
<ExclamationTriangleIcon className="h-6 w-6 text-red-600" aria-hidden="true" />
</span>
<span className="flex items-center justify-start">
<h3 className="text-xl font-medium 2xl:text-2xl">Delete Draft Issue</h3>
@ -124,8 +121,8 @@ export const DeleteDraftIssueModal: React.FC<Props> = (props) => {
<span className="break-words font-medium text-custom-text-100">
{data?.project_detail.identifier}-{data?.sequence_id}
</span>
{""}? All of the data related to the draft issue will be permanently removed.
This action cannot be undone.
{""}? All of the data related to the draft issue will be permanently removed. This action cannot
be undone.
</p>
</span>
<div className="flex justify-end gap-2">

View File

@ -7,7 +7,7 @@ import { mutate } from "swr";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// services
import issueServices from "services/issues.service";
import issueServices from "services/issue.service";
// hooks
import useIssuesView from "hooks/use-issues-view";
import useCalendarIssuesView from "hooks/use-calendar-issues-view";
@ -37,13 +37,7 @@ type Props = {
onSubmit?: () => Promise<void>;
};
export const DeleteIssueModal: React.FC<Props> = ({
isOpen,
handleClose,
data,
user,
onSubmit,
}) => {
export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data, user, onSubmit }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const router = useRouter();
@ -82,11 +76,7 @@ export const DeleteIssueModal: React.FC<Props> = ({
? VIEW_ISSUES(viewId.toString(), calendarParams)
: PROJECT_ISSUES_LIST_WITH_PARAMS(data.project, calendarParams);
mutate<IIssue[]>(
calendarFetchKey,
(prevData) => (prevData ?? []).filter((p) => p.id !== data.id),
false
);
mutate<IIssue[]>(calendarFetchKey, (prevData) => (prevData ?? []).filter((p) => p.id !== data.id), false);
} else if (displayFilters.layout === "spreadsheet") {
const spreadsheetFetchKey = cycleId
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), spreadsheetParams)
@ -163,8 +153,7 @@ export const DeleteIssueModal: React.FC<Props> = ({
});
};
const handleIssueDelete = () =>
isArchivedIssues ? handleArchivedIssueDeletion() : handleDeletion();
const handleIssueDelete = () => (isArchivedIssues ? handleArchivedIssueDeletion() : handleDeletion());
return (
<Transition.Root show={isOpen} as={React.Fragment}>
@ -196,10 +185,7 @@ export const DeleteIssueModal: React.FC<Props> = ({
<div className="flex flex-col gap-6 p-6">
<div className="flex w-full items-center justify-start gap-6">
<span className="place-items-center rounded-full bg-red-500/20 p-4">
<ExclamationTriangleIcon
className="h-6 w-6 text-red-600"
aria-hidden="true"
/>
<ExclamationTriangleIcon className="h-6 w-6 text-red-600" aria-hidden="true" />
</span>
<span className="flex items-center justify-start">
<h3 className="text-xl font-medium 2xl:text-2xl">Delete Issue</h3>
@ -211,8 +197,8 @@ export const DeleteIssueModal: React.FC<Props> = ({
<span className="break-words font-medium text-custom-text-100">
{data?.project_detail.identifier}-{data?.sequence_id}
</span>
{""}? All of the data related to the issue will be permanently removed. This
action cannot be undone.
{""}? All of the data related to the issue will be permanently removed. This action cannot be
undone.
</p>
</span>
<div className="flex justify-end gap-2">

View File

@ -7,7 +7,7 @@ import { mutate } from "swr";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useUser from "hooks/use-user";
import useIssuesView from "hooks/use-issues-view";
@ -114,8 +114,7 @@ export const CreateUpdateDraftIssueModal: React.FC<IssuesModalProps> = ({
return;
}
if (prePopulateData && prePopulateData.project)
return setActiveProject(prePopulateData.project);
if (prePopulateData && prePopulateData.project) return setActiveProject(prePopulateData.project);
// if data is not present, set active project to the project
// in the url. This has the least priority.

View File

@ -4,7 +4,7 @@ import { useRouter } from "next/router";
import useSWR, { mutate } from "swr";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useUserAuth from "hooks/use-user-auth";
import useToast from "hooks/use-toast";
@ -37,11 +37,7 @@ type Props = {
uneditable?: boolean;
};
export const IssueMainContent: React.FC<Props> = ({
issueDetails,
submitChanges,
uneditable = false,
}) => {
export const IssueMainContent: React.FC<Props> = ({ issueDetails, submitChanges, uneditable = false }) => {
const router = useRouter();
const { workspaceSlug, projectId, issueId, archivedIssueId } = router.query;
@ -55,12 +51,7 @@ export const IssueMainContent: React.FC<Props> = ({
const { data: siblingIssues } = useSWR(
workspaceSlug && projectId && issueDetails?.parent ? SUB_ISSUES(issueDetails.parent) : null,
workspaceSlug && projectId && issueDetails?.parent
? () =>
issuesService.subIssues(
workspaceSlug as string,
projectId as string,
issueDetails.parent ?? ""
)
? () => issuesService.subIssues(workspaceSlug as string, projectId as string, issueDetails.parent ?? "")
: null
);
const siblingIssuesList = siblingIssues?.sub_issues.filter((i) => i.id !== issueDetails.id);
@ -68,12 +59,7 @@ export const IssueMainContent: React.FC<Props> = ({
const { data: issueActivity, mutate: mutateIssueActivity } = useSWR(
workspaceSlug && projectId && issueId ? PROJECT_ISSUES_ACTIVITY(issueId.toString()) : null,
workspaceSlug && projectId && issueId
? () =>
issuesService.getIssueActivities(
workspaceSlug.toString(),
projectId.toString(),
issueId.toString()
)
? () => issuesService.getIssueActivities(workspaceSlug.toString(), projectId.toString(), issueId.toString())
: null
);
@ -81,14 +67,7 @@ export const IssueMainContent: React.FC<Props> = ({
if (!workspaceSlug || !projectId || !issueId) return;
await issuesService
.patchIssueComment(
workspaceSlug as string,
projectId as string,
issueId as string,
commentId,
data,
user
)
.patchIssueComment(workspaceSlug as string, projectId as string, issueId as string, commentId, data, user)
.then(() => mutateIssueActivity());
};
@ -98,13 +77,7 @@ export const IssueMainContent: React.FC<Props> = ({
mutateIssueActivity((prevData: any) => prevData?.filter((p: any) => p.id !== commentId), false);
await issuesService
.deleteIssueComment(
workspaceSlug as string,
projectId as string,
issueId as string,
commentId,
user
)
.deleteIssueComment(workspaceSlug as string, projectId as string, issueId as string, commentId, user)
.then(() => mutateIssueActivity());
};
@ -112,13 +85,7 @@ export const IssueMainContent: React.FC<Props> = ({
if (!workspaceSlug || !issueDetails) return;
await issuesService
.createIssueComment(
workspaceSlug.toString(),
issueDetails.project,
issueDetails.id,
formData,
user
)
.createIssueComment(workspaceSlug.toString(), issueDetails.project, issueDetails.id, formData, user)
.then(() => {
mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id));
})
@ -148,8 +115,7 @@ export const IssueMainContent: React.FC<Props> = ({
}}
/>
<span className="flex-shrink-0 text-custom-text-200">
{issueDetails.parent_detail?.project_detail.identifier}-
{issueDetails.parent_detail?.sequence_id}
{issueDetails.parent_detail?.project_detail.identifier}-{issueDetails.parent_detail?.sequence_id}
</span>
</div>
<span className="truncate text-custom-text-100">
@ -169,9 +135,7 @@ export const IssueMainContent: React.FC<Props> = ({
<CustomMenu.MenuItem
key={issue.id}
renderAs="a"
href={`/${workspaceSlug}/projects/${projectId as string}/issues/${
issue.id
}`}
href={`/${workspaceSlug}/projects/${projectId as string}/issues/${issue.id}`}
className="flex items-center gap-2 py-2"
>
<LayerDiagonalIcon className="h-4 w-4" />

View File

@ -8,7 +8,7 @@ import { mutate } from "swr";
import { Dialog, Transition } from "@headlessui/react";
// services
import modulesService from "services/modules.service";
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
import inboxServices from "services/inbox.service";
// hooks
import useUser from "hooks/use-user";
@ -93,8 +93,10 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
const { groupedIssues, mutateMyIssues } = useMyIssues(workspaceSlug?.toString());
const { setValue: setValueInLocalStorage, clearValue: clearLocalStorageValue } =
useLocalStorage<any>("draftedIssue", {});
const { setValue: setValueInLocalStorage, clearValue: clearLocalStorageValue } = useLocalStorage<any>(
"draftedIssue",
{}
);
const { setToastAlert } = useToast();
@ -201,13 +203,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
};
await inboxServices
.createInboxIssue(
workspaceSlug.toString(),
activeProject.toString(),
inboxId.toString(),
payload,
user
)
.createInboxIssue(workspaceSlug.toString(), activeProject.toString(), inboxId.toString(), payload, user)
.then((res) => {
setToastAlert({
type: "success",
@ -264,8 +260,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
.then(async (res) => {
mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params));
if (payload.cycle && payload.cycle !== "") await addIssueToCycle(res.id, payload.cycle);
if (payload.module && payload.module !== "")
await addIssueToModule(res.id, payload.module);
if (payload.module && payload.module !== "") await addIssueToModule(res.id, payload.module);
if (displayFilters.layout === "calendar") mutate(calendarFetchKey);
if (displayFilters.layout === "gantt_chart")

View File

@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// components
import { DateFilterModal } from "components/core";
// ui
@ -29,12 +29,7 @@ type Props = {
height?: "sm" | "md" | "rg" | "lg";
};
export const MyIssuesSelectFilters: React.FC<Props> = ({
filters,
onSelect,
direction = "right",
height = "md",
}) => {
export const MyIssuesSelectFilters: React.FC<Props> = ({ filters, onSelect, direction = "right", height = "md" }) => {
const [isDateFilterModalOpen, setIsDateFilterModalOpen] = useState(false);
const [dateFilterType, setDateFilterType] = useState<{
title: string;
@ -50,9 +45,7 @@ export const MyIssuesSelectFilters: React.FC<Props> = ({
const { data: labels } = useSWR(
workspaceSlug && fetchLabels ? WORKSPACE_LABELS(workspaceSlug.toString()) : null,
workspaceSlug && fetchLabels
? () => issuesService.getWorkspaceLabels(workspaceSlug.toString())
: null
workspaceSlug && fetchLabels ? () => issuesService.getWorkspaceLabels(workspaceSlug.toString()) : null
);
return (

View File

@ -7,7 +7,7 @@ import useSWR, { mutate } from "swr";
// react-beautiful-dnd
import { DropResult } from "react-beautiful-dnd";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useMyIssues from "hooks/my-issues/use-my-issues";
import useMyIssuesFilters from "hooks/my-issues/use-my-issues-filter";
@ -28,10 +28,7 @@ type Props = {
disableUserActions?: false;
};
export const MyIssuesView: React.FC<Props> = ({
openIssuesListModal,
disableUserActions = false,
}) => {
export const MyIssuesView: React.FC<Props> = ({ openIssuesListModal, disableUserActions = false }) => {
// create issue modal
const [createIssueModal, setCreateIssueModal] = useState(false);
const [preloadedData, setPreloadedData] = useState<
@ -40,9 +37,7 @@ export const MyIssuesView: React.FC<Props> = ({
// update issue modal
const [editIssueModal, setEditIssueModal] = useState(false);
const [issueToEdit, setIssueToEdit] = useState<
(IIssue & { actionType: "edit" | "delete" }) | undefined
>(undefined);
const [issueToEdit, setIssueToEdit] = useState<(IIssue & { actionType: "edit" | "delete" }) | undefined>(undefined);
// delete issue modal
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
@ -57,14 +52,10 @@ export const MyIssuesView: React.FC<Props> = ({
const { user } = useUserAuth();
const { groupedIssues, mutateMyIssues, isEmpty, params } = useMyIssues(workspaceSlug?.toString());
const { filters, setFilters, displayFilters, properties } = useMyIssuesFilters(
workspaceSlug?.toString()
);
const { filters, setFilters, displayFilters, properties } = useMyIssuesFilters(workspaceSlug?.toString());
const { data: labels } = useSWR(
workspaceSlug && (filters?.labels ?? []).length > 0
? WORKSPACE_LABELS(workspaceSlug.toString())
: null,
workspaceSlug && (filters?.labels ?? []).length > 0 ? WORKSPACE_LABELS(workspaceSlug.toString()) : null,
workspaceSlug && (filters?.labels ?? []).length > 0
? () => issuesService.getWorkspaceLabels(workspaceSlug.toString())
: null
@ -82,13 +73,7 @@ export const MyIssuesView: React.FC<Props> = ({
async (result: DropResult) => {
setTrashBox(false);
if (
!result.destination ||
!workspaceSlug ||
!groupedIssues ||
displayFilters?.group_by !== "priority"
)
return;
if (!result.destination || !workspaceSlug || !groupedIssues || displayFilters?.group_by !== "priority") return;
const { source, destination } = result;
@ -120,14 +105,8 @@ export const MyIssuesView: React.FC<Props> = ({
return {
...prevData,
[sourceGroup]: orderArrayBy(
sourceGroupArray,
displayFilters.order_by ?? "-created_at"
),
[destinationGroup]: orderArrayBy(
destinationGroupArray,
displayFilters.order_by ?? "-created_at"
),
[sourceGroup]: orderArrayBy(sourceGroupArray, displayFilters.order_by ?? "-created_at"),
[destinationGroup]: orderArrayBy(destinationGroupArray, displayFilters.order_by ?? "-created_at"),
};
},
false
@ -219,15 +198,11 @@ export const MyIssuesView: React.FC<Props> = ({
(key) => filtersToDisplay[key as keyof IIssueFilterOptions] === null
);
const areFiltersApplied =
Object.keys(filtersToDisplay).length > 0 &&
nullFilters.length !== Object.keys(filtersToDisplay).length;
Object.keys(filtersToDisplay).length > 0 && nullFilters.length !== Object.keys(filtersToDisplay).length;
const isSubscribedIssuesRoute = router.pathname.includes("subscribed");
const isMySubscribedIssues =
(filters.subscriber &&
filters.subscriber.length > 0 &&
router.pathname.includes("my-issues")) ??
false;
(filters.subscriber && filters.subscriber.length > 0 && router.pathname.includes("my-issues")) ?? false;
const disableAddIssueOption = isSubscribedIssuesRoute || isMySubscribedIssues;

View File

@ -1,7 +1,7 @@
import useSWR, { mutate } from "swr";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useUser from "hooks/use-user";
import useToast from "hooks/use-toast";
@ -78,10 +78,7 @@ export const PeekOverviewIssueActivity: React.FC<Props> = ({ workspaceSlug, issu
showAccessSpecifier={projectDetails && projectDetails.is_deployed}
/>
<div className="mt-4">
<AddComment
onSubmit={handleAddComment}
showAccessSpecifier={projectDetails && projectDetails.is_deployed}
/>
<AddComment onSubmit={handleAddComment} showAccessSpecifier={projectDetails && projectDetails.is_deployed} />
</div>
</div>
</div>

View File

@ -7,17 +7,11 @@ import useSWR from "swr";
// headless ui
import { Combobox, Transition } from "@headlessui/react";
// services
import issuesServices from "services/issues.service";
import issuesServices from "services/issue.service";
// ui
import { IssueLabelsList } from "components/ui";
// icons
import {
CheckIcon,
MagnifyingGlassIcon,
PlusIcon,
RectangleGroupIcon,
TagIcon,
} from "@heroicons/react/24/outline";
import { CheckIcon, MagnifyingGlassIcon, PlusIcon, RectangleGroupIcon, TagIcon } from "@heroicons/react/24/outline";
// types
import type { IIssueLabels } from "types";
// fetch-keys
@ -39,24 +33,14 @@ export const IssueLabelSelect: React.FC<Props> = ({ setIsOpen, value, onChange,
const { data: issueLabels } = useSWR<IIssueLabels[]>(
projectId ? PROJECT_ISSUE_LABELS(projectId) : null,
workspaceSlug && projectId
? () => issuesServices.getIssueLabels(workspaceSlug as string, projectId)
: null
workspaceSlug && projectId ? () => issuesServices.getIssueLabels(workspaceSlug as string, projectId) : null
);
const filteredOptions =
query === ""
? issueLabels
: issueLabels?.filter((l) => l.name.toLowerCase().includes(query.toLowerCase()));
query === "" ? issueLabels : issueLabels?.filter((l) => l.name.toLowerCase().includes(query.toLowerCase()));
return (
<Combobox
as="div"
value={value}
onChange={(val) => onChange(val)}
className="relative flex-shrink-0"
multiple
>
<Combobox as="div" value={value} onChange={(val) => onChange(val)} className="relative flex-shrink-0" multiple>
{({ open }: any) => (
<>
<Combobox.Button className="flex items-center gap-2 cursor-pointer text-xs text-custom-text-200">
@ -129,11 +113,7 @@ export const IssueLabelSelect: React.FC<Props> = ({ setIsOpen, value, onChange,
<span>{label.name}</span>
</div>
<div className="flex items-center justify-center rounded p-1">
<CheckIcon
className={`h-3 w-3 ${
selected ? "opacity-100" : "opacity-0"
}`}
/>
<CheckIcon className={`h-3 w-3 ${selected ? "opacity-100" : "opacity-0"}`} />
</div>
</div>
)}
@ -168,11 +148,7 @@ export const IssueLabelSelect: React.FC<Props> = ({ setIsOpen, value, onChange,
<span>{child.name}</span>
</div>
<div className="flex items-center justify-center rounded p-1">
<CheckIcon
className={`h-3 w-3 ${
selected ? "opacity-100" : "opacity-0"
}`}
/>
<CheckIcon className={`h-3 w-3 ${selected ? "opacity-100" : "opacity-0"}`} />
</div>
</div>
)}

View File

@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import stateService from "services/state.service";
import stateService from "services/project_state.service";
// ui
import { CustomSearchSelect } from "components/ui";
// icons
@ -30,9 +30,7 @@ export const IssueStateSelect: React.FC<Props> = ({ setIsOpen, value, onChange,
const { data: stateGroups } = useSWR(
workspaceSlug && projectId ? STATES_LIST(projectId) : null,
workspaceSlug && projectId
? () => stateService.getStates(workspaceSlug as string, projectId)
: null
workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId) : null
);
const states = getStatesList(stateGroups);
@ -60,10 +58,7 @@ export const IssueStateSelect: React.FC<Props> = ({ setIsOpen, value, onChange,
{selectedOption ? (
<StateGroupIcon stateGroup={selectedOption.group} color={selectedOption.color} />
) : currentDefaultState ? (
<StateGroupIcon
stateGroup={currentDefaultState.group}
color={currentDefaultState.color}
/>
<StateGroupIcon stateGroup={currentDefaultState.group} color={currentDefaultState.color} />
) : (
<Squares2X2Icon className="h-3.5 w-3.5 text-custom-text-200" />
)}

View File

@ -7,7 +7,7 @@ import { UseFormWatch } from "react-hook-form";
import useToast from "hooks/use-toast";
import useUser from "hooks/use-user";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// components
import { ExistingIssuesListModal } from "components/core";
// icons
@ -23,12 +23,7 @@ type Props = {
disabled?: boolean;
};
export const SidebarBlockedSelect: React.FC<Props> = ({
issueId,
submitChanges,
watch,
disabled = false,
}) => {
export const SidebarBlockedSelect: React.FC<Props> = ({ issueId, submitChanges, watch, disabled = false }) => {
const [isBlockedModalOpen, setIsBlockedModalOpen] = useState(false);
const { user } = useUser();
@ -80,10 +75,7 @@ export const SidebarBlockedSelect: React.FC<Props> = ({
})
.then((response) => {
submitChanges({
related_issues: [
...watch("related_issues")?.filter((i) => i.relation_type !== "blocked_by"),
...response,
],
related_issues: [...watch("related_issues")?.filter((i) => i.relation_type !== "blocked_by"), ...response],
});
});
@ -127,9 +119,7 @@ export const SidebarBlockedSelect: React.FC<Props> = ({
type="button"
className="opacity-0 duration-300 group-hover:opacity-100"
onClick={() => {
const updatedRelations = watch("related_issues")?.filter(
(i) => i.id !== relation.id
);
const updatedRelations = watch("related_issues")?.filter((i) => i.id !== relation.id);
submitChanges({
related_issues: updatedRelations,

View File

@ -10,7 +10,7 @@ import useUser from "hooks/use-user";
// components
import { ExistingIssuesListModal } from "components/core";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// icons
import { XMarkIcon } from "@heroicons/react/24/outline";
import { BlockerIcon } from "components/icons";
@ -24,12 +24,7 @@ type Props = {
disabled?: boolean;
};
export const SidebarBlockerSelect: React.FC<Props> = ({
issueId,
submitChanges,
watch,
disabled = false,
}) => {
export const SidebarBlockerSelect: React.FC<Props> = ({ issueId, submitChanges, watch, disabled = false }) => {
const [isBlockerModalOpen, setIsBlockerModalOpen] = useState(false);
const { user } = useUser();
@ -42,8 +37,7 @@ export const SidebarBlockerSelect: React.FC<Props> = ({
setIsBlockerModalOpen(false);
};
const blockerIssue =
watch("issue_relations")?.filter((i) => i.relation_type === "blocked_by") || [];
const blockerIssue = watch("issue_relations")?.filter((i) => i.relation_type === "blocked_by") || [];
const onSubmit = async (data: ISearchIssueResponse[]) => {
if (data.length === 0) {

View File

@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import useSWR, { mutate } from "swr";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
import cyclesService from "services/cycles.service";
// ui
import { Spinner, CustomSelect, Tooltip } from "components/ui";
@ -22,23 +22,14 @@ type Props = {
disabled?: boolean;
};
export const SidebarCycleSelect: React.FC<Props> = ({
issueDetail,
handleCycleChange,
disabled = false,
}) => {
export const SidebarCycleSelect: React.FC<Props> = ({ issueDetail, handleCycleChange, disabled = false }) => {
const router = useRouter();
const { workspaceSlug, projectId, issueId } = router.query;
const { data: incompleteCycles } = useSWR(
workspaceSlug && projectId ? INCOMPLETE_CYCLES_LIST(projectId as string) : null,
workspaceSlug && projectId
? () =>
cyclesService.getCyclesWithParams(
workspaceSlug as string,
projectId as string,
"incomplete"
)
? () => cyclesService.getCyclesWithParams(workspaceSlug as string, projectId as string, "incomplete")
: null
);
@ -63,21 +54,14 @@ export const SidebarCycleSelect: React.FC<Props> = ({
<CustomSelect
customButton={
<div>
<Tooltip
position="left"
tooltipContent={`${issueCycle ? issueCycle.cycle_detail.name : "No cycle"}`}
>
<Tooltip position="left" tooltipContent={`${issueCycle ? issueCycle.cycle_detail.name : "No cycle"}`}>
<button
type="button"
className={`bg-custom-background-80 text-xs rounded px-2.5 py-0.5 w-full flex ${
disabled ? "cursor-not-allowed" : ""
}`}
>
<span
className={`truncate ${
issueCycle ? "text-custom-text-100" : "text-custom-text-200"
}`}
>
<span className={`truncate ${issueCycle ? "text-custom-text-100" : "text-custom-text-200"}`}>
{issueCycle ? issueCycle.cycle_detail.name : "No cycle"}
</span>
</button>

View File

@ -12,7 +12,7 @@ import { X, CopyPlus } from "lucide-react";
import { BlockerIcon } from "components/icons";
import { ExistingIssuesListModal } from "components/core";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// types
import { BlockeIssueDetail, IIssue, ISearchIssueResponse } from "types";

View File

@ -11,7 +11,7 @@ import { TwitterPicker } from "react-color";
// headless ui
import { Listbox, Popover, Transition } from "@headlessui/react";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useUser from "hooks/use-user";
// ui
@ -66,25 +66,21 @@ export const SidebarLabelSelect: React.FC<Props> = ({
const { data: issueLabels, mutate: issueLabelMutate } = useSWR<IIssueLabels[]>(
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null,
workspaceSlug && projectId
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string)
: null
workspaceSlug && projectId ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) : null
);
const handleNewLabel = async (formData: Partial<IIssueLabels>) => {
if (!workspaceSlug || !projectId || isSubmitting) return;
await issuesService
.createIssueLabel(workspaceSlug as string, projectId as string, formData, user)
.then((res) => {
reset(defaultValues);
await issuesService.createIssueLabel(workspaceSlug as string, projectId as string, formData, user).then((res) => {
reset(defaultValues);
issueLabelMutate((prevData: any) => [...(prevData ?? []), res], false);
issueLabelMutate((prevData: any) => [...(prevData ?? []), res], false);
submitChanges({ labels_list: [...(issueDetails?.labels ?? []), res.id] });
submitChanges({ labels_list: [...(issueDetails?.labels ?? []), res.id] });
setCreateLabelForm(false);
});
setCreateLabelForm(false);
});
};
useEffect(() => {
@ -165,9 +161,7 @@ export const SidebarLabelSelect: React.FC<Props> = ({
{issueLabels ? (
issueLabels.length > 0 ? (
issueLabels.map((label: IIssueLabels) => {
const children = issueLabels?.filter(
(l) => l.parent === label.id
);
const children = issueLabels?.filter((l) => l.parent === label.id);
if (children.length === 0) {
if (!label.parent)
@ -175,9 +169,7 @@ export const SidebarLabelSelect: React.FC<Props> = ({
<Listbox.Option
key={label.id}
className={({ active, selected }) =>
`${
active || selected ? "bg-custom-background-90" : ""
} ${
`${active || selected ? "bg-custom-background-90" : ""} ${
selected ? "" : "text-custom-text-200"
} flex cursor-pointer select-none items-center gap-2 truncate p-2`
}
@ -186,10 +178,7 @@ export const SidebarLabelSelect: React.FC<Props> = ({
<span
className="h-2 w-2 flex-shrink-0 rounded-full"
style={{
backgroundColor:
label.color && label.color !== ""
? label.color
: "#000",
backgroundColor: label.color && label.color !== "" ? label.color : "#000",
}}
/>
{label.name}
@ -207,11 +196,7 @@ export const SidebarLabelSelect: React.FC<Props> = ({
<Listbox.Option
key={child.id}
className={({ active, selected }) =>
`${
active || selected
? "bg-custom-background-100"
: ""
} ${
`${active || selected ? "bg-custom-background-100" : ""} ${
selected ? "" : "text-custom-text-200"
} flex cursor-pointer select-none items-center gap-2 truncate p-2`
}
@ -248,9 +233,7 @@ export const SidebarLabelSelect: React.FC<Props> = ({
<button
type="button"
className={`flex ${
isNotAllowed || uneditable
? "cursor-not-allowed"
: "cursor-pointer hover:bg-custom-background-90"
isNotAllowed || uneditable ? "cursor-not-allowed" : "cursor-pointer hover:bg-custom-background-90"
} items-center gap-1 rounded-2xl border border-custom-border-100 px-2 py-0.5 text-xs text-custom-text-200`}
onClick={() => setCreateLabelForm((prevData) => !prevData)}
disabled={uneditable}
@ -326,11 +309,7 @@ export const SidebarLabelSelect: React.FC<Props> = ({
>
<XMarkIcon className="h-4 w-4 text-white" />
</button>
<button
type="submit"
className="grid place-items-center rounded bg-green-500 p-2.5"
disabled={isSubmitting}
>
<button type="submit" className="grid place-items-center rounded bg-green-500 p-2.5" disabled={isSubmitting}>
<PlusIcon className="h-4 w-4 text-white" />
</button>
</form>

View File

@ -12,7 +12,7 @@ import { BlockerIcon, RelatedIcon } from "components/icons";
// components
import { ExistingIssuesListModal } from "components/core";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// types
import { BlockeIssueDetail, IIssue, ISearchIssueResponse } from "types";

View File

@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import stateService from "services/state.service";
import stateService from "services/project_state.service";
// ui
import { Spinner, CustomSelect } from "components/ui";
// icons
@ -28,9 +28,7 @@ export const SidebarStateSelect: React.FC<Props> = ({ value, onChange, disabled
const { data: stateGroups } = useSWR(
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
workspaceSlug && projectId
? () => stateService.getStates(workspaceSlug as string, projectId as string)
: null
workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null
);
const states = getStatesList(stateGroups);

View File

@ -12,7 +12,7 @@ import useUserAuth from "hooks/use-user-auth";
import useUserIssueNotificationSubscription from "hooks/use-issue-notification-subscription";
import useEstimateOption from "hooks/use-estimate-option";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
import modulesService from "services/modules.service";
// contexts
import { useProjectMyMembership } from "contexts/project-member.context";
@ -103,8 +103,11 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
const { isEstimateActive } = useEstimateOption();
const { loading, handleSubscribe, handleUnsubscribe, subscribed } =
useUserIssueNotificationSubscription(workspaceSlug, projectId, issueId);
const { loading, handleSubscribe, handleUnsubscribe, subscribed } = useUserIssueNotificationSubscription(
workspaceSlug,
projectId,
issueId
);
const { memberRole } = useProjectMyMembership();
@ -198,13 +201,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
);
await issuesService
.updateIssueLink(
workspaceSlug as string,
projectId as string,
issueDetail.id,
linkId,
payload
)
.updateIssueLink(workspaceSlug as string, projectId as string, issueDetail.id, linkId, payload)
.then((res) => {
mutate(ISSUE_DETAILS(issueDetail.id));
})
@ -235,12 +232,9 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
};
const handleCopyText = () => {
const originURL =
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
copyTextToClipboard(
`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issueDetail?.id}`
).then(() => {
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issueDetail?.id}`).then(() => {
setToastAlert({
type: "success",
title: "Link Copied!",
@ -264,9 +258,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
fieldsToShow.includes("dueDate");
const showThirdSection =
fieldsToShow.includes("all") ||
fieldsToShow.includes("cycle") ||
fieldsToShow.includes("module");
fieldsToShow.includes("all") || fieldsToShow.includes("cycle") || fieldsToShow.includes("module");
const startDate = watchIssue("start_date");
const targetDate = watchIssue("target_date");
@ -413,30 +405,27 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
</div>
</div>
)}
{(fieldsToShow.includes("all") || fieldsToShow.includes("estimate")) &&
isEstimateActive && (
<div className="flex flex-wrap items-center py-2">
<div className="flex items-center gap-x-2 text-sm text-custom-text-200 sm:basis-1/2">
<PlayIcon className="h-4 w-4 flex-shrink-0 -rotate-90" />
<p>Estimate</p>
</div>
<div className="sm:basis-1/2">
<Controller
control={control}
name="estimate_point"
render={({ field: { value } }) => (
<SidebarEstimateSelect
value={value}
onChange={(val: number | null) =>
submitChanges({ estimate_point: val })
}
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
/>
)}
/>
</div>
{(fieldsToShow.includes("all") || fieldsToShow.includes("estimate")) && isEstimateActive && (
<div className="flex flex-wrap items-center py-2">
<div className="flex items-center gap-x-2 text-sm text-custom-text-200 sm:basis-1/2">
<PlayIcon className="h-4 w-4 flex-shrink-0 -rotate-90" />
<p>Estimate</p>
</div>
)}
<div className="sm:basis-1/2">
<Controller
control={control}
name="estimate_point"
render={({ field: { value } }) => (
<SidebarEstimateSelect
value={value}
onChange={(val: number | null) => submitChanges({ estimate_point: val })}
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
/>
)}
/>
</div>
</div>
)}
</div>
)}
{showSecondSection && (

View File

@ -8,7 +8,7 @@ import useSWR, { mutate } from "swr";
// headless ui
import { Disclosure, Transition } from "@headlessui/react";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// contexts
import { useProjectMyMembership } from "contexts/project-member.context";
// components
@ -126,10 +126,7 @@ export const SubIssuesList: FC<Props> = ({ parentIssue, user, disabled = false }
<div className="flex items-center justify-start gap-3 text-custom-text-200">
<Disclosure.Button className="flex items-center gap-1 rounded px-2 py-1 text-xs text-custom-text-100 hover:bg-custom-background-80">
<ChevronRightIcon className={`h-3 w-3 ${open ? "rotate-90" : ""}`} />
Sub-issues{" "}
<span className="ml-1 text-custom-text-200">
{subIssuesResponse.sub_issues.length}
</span>
Sub-issues <span className="ml-1 text-custom-text-200">{subIssuesResponse.sub_issues.length}</span>
</Disclosure.Button>
<div className="flex w-60 items-center gap-2">
<div className="bar relative h-1.5 w-full rounded bg-custom-background-80">
@ -186,10 +183,7 @@ export const SubIssuesList: FC<Props> = ({ parentIssue, user, disabled = false }
>
<Disclosure.Panel className="mt-3 flex flex-col gap-y-1">
{subIssuesResponse.sub_issues.map((issue) => (
<Link
key={issue.id}
href={`/${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`}
>
<Link key={issue.id} href={`/${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`}>
<a className="group flex items-center justify-between gap-2 rounded p-2 hover:bg-custom-background-90">
<div className="flex items-center gap-2 rounded text-xs">
<span
@ -240,9 +234,7 @@ export const SubIssuesList: FC<Props> = ({ parentIssue, user, disabled = false }
noChevron
>
<CustomMenu.MenuItem onClick={handleCreateIssueModal}>Create new</CustomMenu.MenuItem>
<CustomMenu.MenuItem onClick={() => setSubIssuesListModal(true)}>
Add an existing issue
</CustomMenu.MenuItem>
<CustomMenu.MenuItem onClick={() => setSubIssuesListModal(true)}>Add an existing issue</CustomMenu.MenuItem>
</CustomMenu>
)
)}

View File

@ -6,7 +6,7 @@ import useSWR from "swr";
// services
import projectService from "services/project.service";
import trackEventServices from "services/track-event.service";
import trackEventServices from "services/track_event.service";
// ui
import { AssigneesList, Avatar, CustomSearchSelect, Icon, Tooltip } from "components/ui";
// icons

View File

@ -5,7 +5,7 @@ import { CustomDatePicker, Tooltip } from "components/ui";
// helpers
import { findHowManyDaysLeft, renderShortDateWithYearFormat } from "helpers/date-time.helper";
// services
import trackEventServices from "services/track-event.service";
import trackEventServices from "services/track_event.service";
// types
import { ICurrentUserResponse, IIssue } from "types";
import useIssuesView from "hooks/use-issues-view";
@ -42,9 +42,7 @@ export const ViewDueDateSelect: React.FC<Props> = ({
return (
<Tooltip
tooltipHeading="Due date"
tooltipContent={
issue.target_date ? renderShortDateWithYearFormat(issue.target_date) ?? "N/A" : "N/A"
}
tooltipContent={issue.target_date ? renderShortDateWithYearFormat(issue.target_date) ?? "N/A" : "N/A"}
position={tooltipPosition}
>
<div
@ -80,9 +78,7 @@ export const ViewDueDateSelect: React.FC<Props> = ({
);
}}
className={`${issue?.target_date ? "w-[6.5rem]" : "w-[5rem] text-center"} ${
displayFilters.layout === "kanban"
? "bg-custom-background-90"
: "bg-custom-background-100"
displayFilters.layout === "kanban" ? "bg-custom-background-90" : "bg-custom-background-100"
}`}
minDate={minDate ?? undefined}
noBorder={noBorder}

View File

@ -3,7 +3,7 @@ import React from "react";
import { useRouter } from "next/router";
// services
import trackEventServices from "services/track-event.service";
import trackEventServices from "services/track_event.service";
// hooks
import useEstimateOption from "hooks/use-estimate-option";
// ui

View File

@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// component
import { CreateLabelModal } from "components/labels";
// ui
@ -45,9 +45,7 @@ export const ViewLabelSelect: React.FC<Props> = ({
const { data: issueLabels } = useSWR<IIssueLabels[]>(
projectId ? PROJECT_ISSUE_LABELS(projectId.toString()) : null,
workspaceSlug && projectId
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string)
: null
workspaceSlug && projectId ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) : null
);
const options = issueLabels?.map((label) => ({

View File

@ -3,7 +3,7 @@ import React from "react";
import { useRouter } from "next/router";
// services
import trackEventServices from "services/track-event.service";
import trackEventServices from "services/track_event.service";
// ui
import { CustomSelect, Tooltip } from "components/ui";
// icons
@ -61,9 +61,9 @@ export const ViewPrioritySelect: React.FC<Props> = ({
customButton={
<button
type="button"
className={`grid place-items-center rounded ${
isNotAllowed ? "cursor-not-allowed" : "cursor-pointer"
} ${noBorder ? "" : "h-6 w-6 border shadow-sm"} ${
className={`grid place-items-center rounded ${isNotAllowed ? "cursor-not-allowed" : "cursor-pointer"} ${
noBorder ? "" : "h-6 w-6 border shadow-sm"
} ${
noBorder
? ""
: issue.priority === "urgent"
@ -71,11 +71,7 @@ export const ViewPrioritySelect: React.FC<Props> = ({
: "border-custom-border-300 bg-custom-background-100"
} items-center`}
>
<Tooltip
tooltipHeading="Priority"
tooltipContent={issue.priority ?? "None"}
position={tooltipPosition}
>
<Tooltip tooltipHeading="Priority" tooltipContent={issue.priority ?? "None"} position={tooltipPosition}>
<span className="flex gap-1 items-center text-custom-text-200 text-xs">
<PriorityIcon
priority={issue.priority}

View File

@ -5,7 +5,7 @@ import { CustomDatePicker, Tooltip } from "components/ui";
// helpers
import { findHowManyDaysLeft, renderShortDateWithYearFormat } from "helpers/date-time.helper";
// services
import trackEventServices from "services/track-event.service";
import trackEventServices from "services/track_event.service";
// types
import { ICurrentUserResponse, IIssue } from "types";
import useIssuesView from "hooks/use-issues-view";
@ -42,9 +42,7 @@ export const ViewStartDateSelect: React.FC<Props> = ({
return (
<Tooltip
tooltipHeading="Start date"
tooltipContent={
issue.start_date ? renderShortDateWithYearFormat(issue.start_date) ?? "N/A" : "N/A"
}
tooltipContent={issue.start_date ? renderShortDateWithYearFormat(issue.start_date) ?? "N/A" : "N/A"}
position={tooltipPosition}
>
<div className="group flex-shrink-0 relative max-w-[6.5rem]">
@ -72,9 +70,7 @@ export const ViewStartDateSelect: React.FC<Props> = ({
);
}}
className={`${issue?.start_date ? "w-[6.5rem]" : "w-[5rem] text-center"} ${
displayFilters.layout === "kanban"
? "bg-custom-background-90"
: "bg-custom-background-100"
displayFilters.layout === "kanban" ? "bg-custom-background-90" : "bg-custom-background-100"
}`}
maxDate={maxDate ?? undefined}
noBorder={noBorder}

View File

@ -5,8 +5,8 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import stateService from "services/state.service";
import trackEventServices from "services/track-event.service";
import stateService from "services/project_state.service";
import trackEventServices from "services/track_event.service";
// ui
import { CustomSearchSelect, Tooltip } from "components/ui";
// icons
@ -48,9 +48,7 @@ export const ViewStateSelect: React.FC<Props> = ({
const { data: stateGroups } = useSWR(
workspaceSlug && issue && fetchStates ? STATES_LIST(issue.project) : null,
workspaceSlug && issue && fetchStates
? () => stateService.getStates(workspaceSlug as string, issue.project)
: null
workspaceSlug && issue && fetchStates ? () => stateService.getStates(workspaceSlug as string, issue.project) : null
);
const states = getStatesList(stateGroups);
@ -68,16 +66,10 @@ export const ViewStateSelect: React.FC<Props> = ({
const selectedOption = issue.state_detail;
const stateLabel = (
<Tooltip
tooltipHeading="State"
tooltipContent={selectedOption?.name ?? ""}
position={tooltipPosition}
>
<Tooltip tooltipHeading="State" tooltipContent={selectedOption?.name ?? ""} position={tooltipPosition}>
<div className="flex items-center cursor-pointer w-full gap-2 text-custom-text-200">
<span className="h-3.5 w-3.5">
{selectedOption && (
<StateGroupIcon stateGroup={selectedOption.group} color={selectedOption.color} />
)}
{selectedOption && <StateGroupIcon stateGroup={selectedOption.group} color={selectedOption.color} />}
</span>
<span className="truncate">{selectedOption?.name ?? "State"}</span>
</div>

View File

@ -11,7 +11,7 @@ import { TwitterPicker } from "react-color";
// headless ui
import { Dialog, Popover, Transition } from "@headlessui/react";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// ui
import { Input, PrimaryButton, SecondaryButton } from "components/ui";
// icons
@ -36,13 +36,7 @@ const defaultValues: Partial<IState> = {
color: "rgb(var(--color-text-200))",
};
export const CreateLabelModal: React.FC<Props> = ({
isOpen,
projectId,
handleClose,
user,
onSuccess,
}) => {
export const CreateLabelModal: React.FC<Props> = ({ isOpen, projectId, handleClose, user, onSuccess }) => {
const router = useRouter();
const { workspaceSlug } = router.query;
@ -73,11 +67,7 @@ export const CreateLabelModal: React.FC<Props> = ({
await issuesService
.createIssueLabel(workspaceSlug as string, projectId as string, formData, user)
.then((res) => {
mutate<IIssueLabels[]>(
PROJECT_ISSUE_LABELS(projectId),
(prevData) => [res, ...(prevData ?? [])],
false
);
mutate<IIssueLabels[]>(PROJECT_ISSUE_LABELS(projectId), (prevData) => [res, ...(prevData ?? [])], false);
onClose();
if (onSuccess) onSuccess(res);
})
@ -115,10 +105,7 @@ export const CreateLabelModal: React.FC<Props> = ({
<Dialog.Panel className="relative transform rounded-lg bg-custom-background-90 px-4 pt-5 pb-4 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-custom-text-100"
>
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-custom-text-100">
Create Label
</Dialog.Title>
<div className="mt-8 flex items-center gap-2">

View File

@ -13,7 +13,7 @@ import { TwitterPicker } from "react-color";
// headless ui
import { Popover, Transition } from "@headlessui/react";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// ui
import { Input, PrimaryButton, SecondaryButton } from "components/ui";
// types
@ -35,174 +35,157 @@ const defaultValues: Partial<IIssueLabels> = {
color: "rgb(var(--color-text-200))",
};
export const CreateUpdateLabelInline = forwardRef<HTMLDivElement, Props>(
function CreateUpdateLabelInline(props, ref) {
const { labelForm, setLabelForm, isUpdating, labelToUpdate, onClose } = props;
export const CreateUpdateLabelInline = forwardRef<HTMLDivElement, Props>(function CreateUpdateLabelInline(props, ref) {
const { labelForm, setLabelForm, isUpdating, labelToUpdate, onClose } = props;
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
const { user } = useUserAuth();
const { user } = useUserAuth();
const {
handleSubmit,
control,
register,
reset,
formState: { errors, isSubmitting },
watch,
setValue,
} = useForm<IIssueLabels>({
defaultValues,
});
const {
handleSubmit,
control,
register,
reset,
formState: { errors, isSubmitting },
watch,
setValue,
} = useForm<IIssueLabels>({
defaultValues,
});
const handleClose = () => {
setLabelForm(false);
reset(defaultValues);
if (onClose) onClose();
};
const handleClose = () => {
setLabelForm(false);
reset(defaultValues);
if (onClose) onClose();
};
const handleLabelCreate: SubmitHandler<IIssueLabels> = async (formData) => {
if (!workspaceSlug || !projectId || isSubmitting) return;
const handleLabelCreate: SubmitHandler<IIssueLabels> = async (formData) => {
if (!workspaceSlug || !projectId || isSubmitting) return;
await issuesService
.createIssueLabel(workspaceSlug as string, projectId as string, formData, user)
.then((res) => {
mutate<IIssueLabels[]>(
PROJECT_ISSUE_LABELS(projectId as string),
(prevData) => [res, ...(prevData ?? [])],
false
);
handleClose();
});
};
const handleLabelUpdate: SubmitHandler<IIssueLabels> = async (formData) => {
if (!workspaceSlug || !projectId || isSubmitting) return;
await issuesService
.patchIssueLabel(
workspaceSlug as string,
projectId as string,
labelToUpdate?.id ?? "",
formData,
user
)
.then(() => {
reset(defaultValues);
mutate<IIssueLabels[]>(
PROJECT_ISSUE_LABELS(projectId as string),
(prevData) =>
prevData?.map((p) => (p.id === labelToUpdate?.id ? { ...p, ...formData } : p)),
false
);
handleClose();
});
};
useEffect(() => {
if (!labelForm && isUpdating) return;
reset();
}, [labelForm, isUpdating, reset]);
useEffect(() => {
if (!labelToUpdate) return;
setValue(
"color",
labelToUpdate.color && labelToUpdate.color !== "" ? labelToUpdate.color : "#000"
await issuesService.createIssueLabel(workspaceSlug as string, projectId as string, formData, user).then((res) => {
mutate<IIssueLabels[]>(
PROJECT_ISSUE_LABELS(projectId as string),
(prevData) => [res, ...(prevData ?? [])],
false
);
setValue("name", labelToUpdate.name);
}, [labelToUpdate, setValue]);
handleClose();
});
};
useEffect(() => {
if (labelToUpdate) {
setValue(
"color",
labelToUpdate.color && labelToUpdate.color !== "" ? labelToUpdate.color : "#000"
const handleLabelUpdate: SubmitHandler<IIssueLabels> = async (formData) => {
if (!workspaceSlug || !projectId || isSubmitting) return;
await issuesService
.patchIssueLabel(workspaceSlug as string, projectId as string, labelToUpdate?.id ?? "", formData, user)
.then(() => {
reset(defaultValues);
mutate<IIssueLabels[]>(
PROJECT_ISSUE_LABELS(projectId as string),
(prevData) => prevData?.map((p) => (p.id === labelToUpdate?.id ? { ...p, ...formData } : p)),
false
);
return;
}
handleClose();
});
};
setValue("color", getRandomLabelColor());
}, [labelToUpdate, setValue]);
useEffect(() => {
if (!labelForm && isUpdating) return;
return (
<div
className={`flex scroll-m-8 items-center gap-2 rounded border border-custom-border-200 bg-custom-background-100 px-3.5 py-2 ${
labelForm ? "" : "hidden"
}`}
ref={ref}
>
<div className="flex-shrink-0">
<Popover className="relative z-10 flex h-full w-full items-center justify-center">
{({ open }) => (
<>
<Popover.Button
className={`group inline-flex items-center text-base font-medium focus:outline-none ${
open ? "text-custom-text-100" : "text-custom-text-200"
}`}
>
<span
className="h-4 w-4 rounded-full"
style={{
backgroundColor: watch("color"),
}}
reset();
}, [labelForm, isUpdating, reset]);
useEffect(() => {
if (!labelToUpdate) return;
setValue("color", labelToUpdate.color && labelToUpdate.color !== "" ? labelToUpdate.color : "#000");
setValue("name", labelToUpdate.name);
}, [labelToUpdate, setValue]);
useEffect(() => {
if (labelToUpdate) {
setValue("color", labelToUpdate.color && labelToUpdate.color !== "" ? labelToUpdate.color : "#000");
return;
}
setValue("color", getRandomLabelColor());
}, [labelToUpdate, setValue]);
return (
<div
className={`flex scroll-m-8 items-center gap-2 rounded border border-custom-border-200 bg-custom-background-100 px-3.5 py-2 ${
labelForm ? "" : "hidden"
}`}
ref={ref}
>
<div className="flex-shrink-0">
<Popover className="relative z-10 flex h-full w-full items-center justify-center">
{({ open }) => (
<>
<Popover.Button
className={`group inline-flex items-center text-base font-medium focus:outline-none ${
open ? "text-custom-text-100" : "text-custom-text-200"
}`}
>
<span
className="h-4 w-4 rounded-full"
style={{
backgroundColor: watch("color"),
}}
/>
</Popover.Button>
<Transition
as={React.Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute top-full left-0 z-20 mt-3 w-screen max-w-xs px-2 sm:px-0">
<Controller
name="color"
control={control}
render={({ field: { value, onChange } }) => (
<TwitterPicker
colors={LABEL_COLOR_OPTIONS}
color={value}
onChange={(value) => onChange(value.hex)}
/>
)}
/>
</Popover.Button>
<Transition
as={React.Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Popover.Panel className="absolute top-full left-0 z-20 mt-3 w-screen max-w-xs px-2 sm:px-0">
<Controller
name="color"
control={control}
render={({ field: { value, onChange } }) => (
<TwitterPicker
colors={LABEL_COLOR_OPTIONS}
color={value}
onChange={(value) => onChange(value.hex)}
/>
)}
/>
</Popover.Panel>
</Transition>
</>
)}
</Popover>
</div>
<div className="flex flex-1 flex-col justify-center">
<Input
type="text"
id="labelName"
name="name"
register={register}
placeholder="Label title"
validations={{
required: "Label title is required",
}}
error={errors.name}
/>
</div>
<SecondaryButton onClick={() => handleClose()}>Cancel</SecondaryButton>
{isUpdating ? (
<PrimaryButton onClick={handleSubmit(handleLabelUpdate)} loading={isSubmitting}>
{isSubmitting ? "Updating" : "Update"}
</PrimaryButton>
) : (
<PrimaryButton onClick={handleSubmit(handleLabelCreate)} loading={isSubmitting}>
{isSubmitting ? "Adding" : "Add"}
</PrimaryButton>
)}
</Popover.Panel>
</Transition>
</>
)}
</Popover>
</div>
);
}
);
<div className="flex flex-1 flex-col justify-center">
<Input
type="text"
id="labelName"
name="name"
register={register}
placeholder="Label title"
validations={{
required: "Label title is required",
}}
error={errors.name}
/>
</div>
<SecondaryButton onClick={() => handleClose()}>Cancel</SecondaryButton>
{isUpdating ? (
<PrimaryButton onClick={handleSubmit(handleLabelUpdate)} loading={isSubmitting}>
{isSubmitting ? "Updating" : "Update"}
</PrimaryButton>
) : (
<PrimaryButton onClick={handleSubmit(handleLabelCreate)} loading={isSubmitting}>
{isSubmitting ? "Adding" : "Add"}
</PrimaryButton>
)}
</div>
);
});

View File

@ -9,7 +9,7 @@ import { Dialog, Transition } from "@headlessui/react";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useToast from "hooks/use-toast";
// ui
@ -95,23 +95,17 @@ export const DeleteLabelModal: React.FC<Props> = ({ isOpen, onClose, data, user
<div className="px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
<ExclamationTriangleIcon
className="h-6 w-6 text-red-600"
aria-hidden="true"
/>
<ExclamationTriangleIcon className="h-6 w-6 text-red-600" aria-hidden="true" />
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-custom-text-100"
>
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-custom-text-100">
Delete Label
</Dialog.Title>
<div className="mt-2">
<p className="text-sm text-custom-text-200">
Are you sure you want to delete label-{" "}
<span className="font-medium text-custom-text-100">{data?.name}</span>?
The label will be removed from all the issues.
<span className="font-medium text-custom-text-100">{data?.name}</span>? The label will be
removed from all the issues.
</p>
</div>
</div>

View File

@ -9,7 +9,7 @@ import { Combobox, Dialog, Transition } from "@headlessui/react";
// icons
import { RectangleStackIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// types
import { ICurrentUserResponse, IIssueLabels } from "types";
// constants
@ -30,9 +30,7 @@ export const LabelsListModal: React.FC<Props> = ({ isOpen, handleClose, parent,
const { data: issueLabels, mutate } = useSWR<IIssueLabels[]>(
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null,
workspaceSlug && projectId
? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string)
: null
workspaceSlug && projectId ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) : null
);
const filteredLabels: IIssueLabels[] =
@ -114,9 +112,7 @@ export const LabelsListModal: React.FC<Props> = ({ isOpen, handleClose, parent,
{filteredLabels.length > 0 && (
<li className="p-2">
{query === "" && (
<h2 className="mt-4 mb-2 px-3 text-xs font-semibold text-custom-text-100">
Labels
</h2>
<h2 className="mt-4 mb-2 px-3 text-xs font-semibold text-custom-text-100">Labels</h2>
)}
<ul className="text-sm text-gray-700">
{filteredLabels.map((label) => {

View File

@ -7,17 +7,11 @@ import { mutate } from "swr";
// headless ui
import { Disclosure, Transition } from "@headlessui/react";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// ui
import { CustomMenu } from "components/ui";
// icons
import {
ChevronDownIcon,
XMarkIcon,
PlusIcon,
PencilIcon,
TrashIcon,
} from "@heroicons/react/24/outline";
import { ChevronDownIcon, XMarkIcon, PlusIcon, PencilIcon, TrashIcon } from "@heroicons/react/24/outline";
import { Component, X } from "lucide-react";
// types
import { ICurrentUserResponse, IIssueLabels } from "types";
@ -110,9 +104,7 @@ export const SingleLabelGroup: React.FC<Props> = ({
<Disclosure.Button>
<span>
<ChevronDownIcon
className={`h-4 w-4 text-custom-sidebar-text-400 ${
!open ? "rotate-90 transform" : ""
}`}
className={`h-4 w-4 text-custom-sidebar-text-400 ${!open ? "rotate-90 transform" : ""}`}
/>
</span>
</Disclosure.Button>
@ -138,8 +130,7 @@ export const SingleLabelGroup: React.FC<Props> = ({
<span
className="h-3.5 w-3.5 flex-shrink-0 rounded-full"
style={{
backgroundColor:
child.color && child.color !== "" ? child.color : "#000000",
backgroundColor: child.color && child.color !== "" ? child.color : "#000000",
}}
/>
{child.name}
@ -169,10 +160,7 @@ export const SingleLabelGroup: React.FC<Props> = ({
</div>
<div className="flex items-center">
<button
className="flex items-center justify-start gap-2"
onClick={handleLabelDelete}
>
<button className="flex items-center justify-start gap-2" onClick={handleLabelDelete}>
<X className="h-[18px] w-[18px] text-custom-sidebar-text-400 flex-shrink-0" />
</button>
</div>

View File

@ -9,7 +9,7 @@ import { PaperAirplaneIcon } from "@heroicons/react/24/outline";
// react-hook-form
import { useForm } from "react-hook-form";
// services
import pagesService from "services/pages.service";
import pagesService from "services/page.service";
// hooks
import useToast from "hooks/use-toast";
@ -81,8 +81,7 @@ export const CreateBlock: React.FC<Props> = ({ user }) => {
};
const handleKeyDown = (e: any) => {
const keyCombination =
((e.ctrlKey || e.metaKey) && e.key === "Enter") || (e.shiftKey && e.key === "Enter");
const keyCombination = ((e.ctrlKey || e.metaKey) && e.key === "Enter") || (e.shiftKey && e.key === "Enter");
if (e.key === "Enter" && !keyCombination) {
if (watch("name") && watch("name") !== "") {

View File

@ -4,8 +4,8 @@ import { mutate } from "swr";
import { SparklesIcon } from "@heroicons/react/24/outline";
import { Controller, useForm } from "react-hook-form";
// services
import pagesService from "services/pages.service";
import issuesService from "services/issues.service";
import pagesService from "services/page.service";
import issuesService from "services/issue.service";
import aiService from "services/ai.service";
// hooks
import useToast from "hooks/use-toast";
@ -195,8 +195,7 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
setToastAlert({
type: "error",
title: "Error!",
message:
"You have reached the maximum number of requests of 50 requests per month per user.",
message: "You have reached the maximum number of requests of 50 requests per month per user.",
});
else
setToastAlert({
@ -294,9 +293,7 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
/>
);
else if (!value || !watch("description_html"))
return (
<div className="h-32 w-full flex items-center justify-center text-custom-text-200 text-sm" />
);
return <div className="h-32 w-full flex items-center justify-center text-custom-text-200 text-sm" />;
return (
<TipTapEditor
@ -351,13 +348,7 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
<div className="flex items-center justify-end gap-2 p-4">
<SecondaryButton onClick={handleClose}>Cancel</SecondaryButton>
<PrimaryButton type="submit" disabled={watch("name") === ""} loading={isSubmitting}>
{data
? isSubmitting
? "Updating..."
: "Update block"
: isSubmitting
? "Adding..."
: "Add block"}
{data ? (isSubmitting ? "Updating..." : "Update block") : isSubmitting ? "Adding..." : "Add block"}
</PrimaryButton>
</div>
</form>
@ -371,9 +362,7 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
onResponse={(response) => {
if (data && handleAiAssistance) {
handleAiAssistance(response);
editorRef.current?.setEditorValue(
`${watch("description_html")}<p>${response}</p>` ?? ""
);
editorRef.current?.setEditorValue(`${watch("description_html")}<p>${response}</p>` ?? "");
} else {
setValue("description", {});
setValue("description_html", `${watch("description_html")}<p>${response}</p>`);

View File

@ -7,7 +7,7 @@ import { mutate } from "swr";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// services
import pagesService from "services/pages.service";
import pagesService from "services/page.service";
// hooks
import useToast from "hooks/use-toast";
// components
@ -15,12 +15,7 @@ import { PageForm } from "./page-form";
// types
import { ICurrentUserResponse, IPage } from "types";
// fetch-keys
import {
ALL_PAGES_LIST,
FAVORITE_PAGES_LIST,
MY_PAGES_LIST,
RECENT_PAGES_LIST,
} from "constants/fetch-keys";
import { ALL_PAGES_LIST, FAVORITE_PAGES_LIST, MY_PAGES_LIST, RECENT_PAGES_LIST } from "constants/fetch-keys";
type Props = {
isOpen: boolean;

View File

@ -7,7 +7,7 @@ import { mutate } from "swr";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// services
import pagesService from "services/pages.service";
import pagesService from "services/page.service";
// hooks
import useToast from "hooks/use-toast";
// ui
@ -17,12 +17,7 @@ import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// types
import type { ICurrentUserResponse, IPage } from "types";
// fetch-keys
import {
ALL_PAGES_LIST,
FAVORITE_PAGES_LIST,
MY_PAGES_LIST,
RECENT_PAGES_LIST,
} from "constants/fetch-keys";
import { ALL_PAGES_LIST, FAVORITE_PAGES_LIST, MY_PAGES_LIST, RECENT_PAGES_LIST } from "constants/fetch-keys";
type TConfirmPageDeletionProps = {
isOpen: boolean;
@ -31,12 +26,7 @@ type TConfirmPageDeletionProps = {
user: ICurrentUserResponse | undefined;
};
export const DeletePageModal: React.FC<TConfirmPageDeletionProps> = ({
isOpen,
setIsOpen,
data,
user,
}) => {
export const DeletePageModal: React.FC<TConfirmPageDeletionProps> = ({ isOpen, setIsOpen, data, user }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const router = useRouter();
@ -121,26 +111,17 @@ export const DeletePageModal: React.FC<TConfirmPageDeletionProps> = ({
<div className="px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-red-500/20 sm:mx-0 sm:h-10 sm:w-10">
<ExclamationTriangleIcon
className="h-6 w-6 text-red-600"
aria-hidden="true"
/>
<ExclamationTriangleIcon className="h-6 w-6 text-red-600" aria-hidden="true" />
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-custom-text-100"
>
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-custom-text-100">
Delete Page
</Dialog.Title>
<div className="mt-2">
<p className="text-sm text-custom-text-200">
Are you sure you want to delete Page-{" "}
<span className="break-words font-medium text-custom-text-100">
{data?.name}
</span>
? All of the data related to the page will be permanently removed. This
action cannot be undone.
<span className="break-words font-medium text-custom-text-100">{data?.name}</span>? All of the
data related to the page will be permanently removed. This action cannot be undone.
</p>
</div>
</div>

View File

@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import pagesService from "services/pages.service";
import pagesService from "services/page.service";
// components
import { PagesView } from "components/pages";
// types

View File

@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import pagesService from "services/pages.service";
import pagesService from "services/page.service";
// components
import { PagesView } from "components/pages";
// types
@ -18,8 +18,7 @@ export const FavoritePagesList: React.FC<TPagesListProps> = ({ viewType }) => {
const { data: pages } = useSWR(
workspaceSlug && projectId ? FAVORITE_PAGES_LIST(projectId as string) : null,
workspaceSlug && projectId
? () =>
pagesService.getPagesWithParams(workspaceSlug as string, projectId as string, "favorite")
? () => pagesService.getPagesWithParams(workspaceSlug as string, projectId as string, "favorite")
: null
);

View File

@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import pagesService from "services/pages.service";
import pagesService from "services/page.service";
// components
import { PagesView } from "components/pages";
// types
@ -18,12 +18,7 @@ export const MyPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
const { data: pages } = useSWR(
workspaceSlug && projectId ? MY_PAGES_LIST(projectId as string) : null,
workspaceSlug && projectId
? () =>
pagesService.getPagesWithParams(
workspaceSlug as string,
projectId as string,
"created_by_me"
)
? () => pagesService.getPagesWithParams(workspaceSlug as string, projectId as string, "created_by_me")
: null
);

View File

@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import pagesService from "services/pages.service";
import pagesService from "services/page.service";
// components
import { PagesView } from "components/pages";
// types
@ -18,12 +18,7 @@ export const OtherPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
const { data: pages } = useSWR(
workspaceSlug && projectId ? OTHER_PAGES_LIST(projectId as string) : null,
workspaceSlug && projectId
? () =>
pagesService.getPagesWithParams(
workspaceSlug as string,
projectId as string,
"created_by_other"
)
? () => pagesService.getPagesWithParams(workspaceSlug as string, projectId as string, "created_by_other")
: null
);

View File

@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import pagesService from "services/pages.service";
import pagesService from "services/page.service";
// components
import { PagesView } from "components/pages";
// ui
@ -28,9 +28,7 @@ export const RecentPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
const { data: pages } = useSWR(
workspaceSlug && projectId ? RECENT_PAGES_LIST(projectId as string) : null,
workspaceSlug && projectId
? () => pagesService.getRecentPages(workspaceSlug as string, projectId as string)
: null
workspaceSlug && projectId ? () => pagesService.getRecentPages(workspaceSlug as string, projectId as string) : null
);
const isEmpty = pages && Object.keys(pages).every((key) => pages[key].length === 0);
@ -44,9 +42,7 @@ export const RecentPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
return (
<div key={key} className="h-full overflow-hidden">
<h2 className="text-xl font-semibold capitalize mb-2">
{replaceUnderscoreIfSnakeCase(key)}
</h2>
<h2 className="text-xl font-semibold capitalize mb-2">{replaceUnderscoreIfSnakeCase(key)}</h2>
<PagesView pages={pages[key as keyof RecentPagesResponse]} viewType={viewType} />
</div>
);

View File

@ -4,18 +4,13 @@ import useSWR, { mutate } from "swr";
import { useRouter } from "next/router";
// services
import pagesService from "services/pages.service";
import pagesService from "services/page.service";
import projectService from "services/project.service";
// hooks
import useToast from "hooks/use-toast";
import useUserAuth from "hooks/use-user-auth";
// components
import {
CreateUpdatePageModal,
DeletePageModal,
SinglePageDetailedItem,
SinglePageListItem,
} from "components/pages";
import { CreateUpdatePageModal, DeletePageModal, SinglePageDetailedItem, SinglePageListItem } from "components/pages";
// ui
import { EmptyState, Loader } from "components/ui";
// icons
@ -91,11 +86,7 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
}),
false
);
mutate<IPage[]>(
FAVORITE_PAGES_LIST(projectId.toString()),
(prevData) => [page, ...(prevData ?? [])],
false
);
mutate<IPage[]>(FAVORITE_PAGES_LIST(projectId.toString()), (prevData) => [page, ...(prevData ?? [])], false);
pagesService
.addPageToFavorites(workspaceSlug.toString(), projectId.toString(), {
@ -185,11 +176,9 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
false
);
pagesService
.patchPage(workspaceSlug.toString(), projectId.toString(), page.id, formData, user)
.then(() => {
mutate(RECENT_PAGES_LIST(projectId.toString()));
});
pagesService.patchPage(workspaceSlug.toString(), projectId.toString(), page.id, formData, user).then(() => {
mutate(RECENT_PAGES_LIST(projectId.toString()));
});
};
return (

View File

@ -10,8 +10,8 @@ import { useForm } from "react-hook-form";
// react-beautiful-dnd
import { Draggable } from "react-beautiful-dnd";
// services
import pagesService from "services/pages.service";
import issuesService from "services/issues.service";
import pagesService from "services/page.service";
import issuesService from "services/issue.service";
import aiService from "services/ai.service";
// hooks
import useToast from "hooks/use-toast";
@ -48,13 +48,7 @@ type Props = {
user: ICurrentUserResponse | undefined;
};
export const SinglePageBlock: React.FC<Props> = ({
block,
projectDetails,
showBlockDetails,
index,
user,
}) => {
export const SinglePageBlock: React.FC<Props> = ({ block, projectDetails, showBlockDetails, index, user }) => {
const [isSyncing, setIsSyncing] = useState(false);
const [createBlockForm, setCreateBlockForm] = useState(false);
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
@ -131,13 +125,7 @@ export const SinglePageBlock: React.FC<Props> = ({
if (!workspaceSlug || !projectId || !pageId) return;
await pagesService
.convertPageBlockToIssue(
workspaceSlug as string,
projectId as string,
pageId as string,
block.id,
user
)
.convertPageBlockToIssue(workspaceSlug as string, projectId as string, pageId as string, block.id, user)
.then((res: IIssue) => {
mutate<IPageBlock[]>(
PAGE_BLOCKS_LIST(pageId as string),
@ -175,13 +163,7 @@ export const SinglePageBlock: React.FC<Props> = ({
);
await pagesService
.deletePageBlock(
workspaceSlug as string,
projectId as string,
pageId as string,
block.id,
user
)
.deletePageBlock(workspaceSlug as string, projectId as string, pageId as string, block.id, user)
.catch(() => {
setToastAlert({
type: "error",
@ -221,8 +203,7 @@ export const SinglePageBlock: React.FC<Props> = ({
setToastAlert({
type: "error",
title: "Error!",
message:
"You have reached the maximum number of requests of 50 requests per month per user.",
message: "You have reached the maximum number of requests of 50 requests per month per user.",
});
else
setToastAlert({
@ -283,12 +264,9 @@ export const SinglePageBlock: React.FC<Props> = ({
};
const handleCopyText = () => {
const originURL =
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
copyTextToClipboard(
`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${block.issue}`
).then(() => {
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${block.issue}`).then(() => {
setToastAlert({
type: "success",
title: "Link Copied!",
@ -343,11 +321,7 @@ export const SinglePageBlock: React.FC<Props> = ({
>
{block.issue && block.sync && (
<div className="flex flex-shrink-0 cursor-default items-center gap-1 rounded py-1 px-1.5 text-xs">
{isSyncing ? (
<ArrowPathIcon className="h-3 w-3 animate-spin" />
) : (
<CheckIcon className="h-3 w-3" />
)}
{isSyncing ? <ArrowPathIcon className="h-3 w-3 animate-spin" /> : <CheckIcon className="h-3 w-3" />}
{isSyncing ? "Syncing..." : "Synced"}
</div>
)}
@ -431,9 +405,7 @@ export const SinglePageBlock: React.FC<Props> = ({
<div className="flex items-center">
{block.issue && (
<div className="mr-1.5 flex">
<Link
href={`/${workspaceSlug}/projects/${projectId}/issues/${block.issue}`}
>
<Link href={`/${workspaceSlug}/projects/${projectId}/issues/${block.issue}`}>
<a className="flex h-6 flex-shrink-0 items-center gap-1 rounded bg-custom-background-80 px-1.5 py-1 text-xs">
<LayerDiagonalIcon height="16" width="16" />
{projectDetails?.identifier}-{block.issue_detail?.sequence_id}

View File

@ -7,7 +7,7 @@ import useSWR from "swr";
// react-beautiful-dnd
import { DropResult } from "react-beautiful-dnd";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
import userService from "services/user.service";
// hooks
import useProfileIssues from "hooks/use-profile-issues";
@ -31,9 +31,7 @@ export const ProfileIssuesView = () => {
// update issue modal
const [editIssueModal, setEditIssueModal] = useState(false);
const [issueToEdit, setIssueToEdit] = useState<
(IIssue & { actionType: "edit" | "delete" }) | undefined
>(undefined);
const [issueToEdit, setIssueToEdit] = useState<(IIssue & { actionType: "edit" | "delete" }) | undefined>(undefined);
// delete issue modal
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
@ -60,19 +58,14 @@ export const ProfileIssuesView = () => {
} = useProfileIssues(workspaceSlug?.toString(), userId?.toString());
const { data: profileData } = useSWR(
workspaceSlug && userId ? USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString()) : null,
workspaceSlug && userId
? USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString())
: null,
workspaceSlug && userId
? () =>
userService.getUserProfileProjectsSegregation(workspaceSlug.toString(), userId.toString())
? () => userService.getUserProfileProjectsSegregation(workspaceSlug.toString(), userId.toString())
: null
);
const { data: labels } = useSWR(
workspaceSlug && (filters?.labels ?? []).length > 0
? WORKSPACE_LABELS(workspaceSlug.toString())
: null,
workspaceSlug && (filters?.labels ?? []).length > 0 ? WORKSPACE_LABELS(workspaceSlug.toString()) : null,
workspaceSlug && (filters?.labels ?? []).length > 0
? () => issuesService.getWorkspaceLabels(workspaceSlug.toString())
: null
@ -90,13 +83,7 @@ export const ProfileIssuesView = () => {
async (result: DropResult) => {
setTrashBox(false);
if (
!result.destination ||
!workspaceSlug ||
!groupedIssues ||
displayFilters?.group_by !== "priority"
)
return;
if (!result.destination || !workspaceSlug || !groupedIssues || displayFilters?.group_by !== "priority") return;
const { source, destination } = result;
@ -125,10 +112,7 @@ export const ProfileIssuesView = () => {
return {
...prevData,
[sourceGroup]: orderArrayBy(sourceGroupArray, displayFilters.order_by ?? "-created_at"),
[destinationGroup]: orderArrayBy(
destinationGroupArray,
displayFilters.order_by ?? "-created_at"
),
[destinationGroup]: orderArrayBy(destinationGroupArray, displayFilters.order_by ?? "-created_at"),
};
}, false);
@ -218,15 +202,11 @@ export const ProfileIssuesView = () => {
(key) => filtersToDisplay[key as keyof IIssueFilterOptions] === null
);
const areFiltersApplied =
Object.keys(filtersToDisplay).length > 0 &&
nullFilters.length !== Object.keys(filtersToDisplay).length;
Object.keys(filtersToDisplay).length > 0 && nullFilters.length !== Object.keys(filtersToDisplay).length;
const isSubscribedIssuesRoute = router.pathname.includes("subscribed");
const isMySubscribedIssues =
(filters.subscriber &&
filters.subscriber.length > 0 &&
router.pathname.includes("my-issues")) ??
false;
(filters.subscriber && filters.subscriber.length > 0 && router.pathname.includes("my-issues")) ?? false;
const disableAddIssueOption = isSubscribedIssuesRoute || isMySubscribedIssues;

View File

@ -6,21 +6,14 @@ import { Controller, useForm } from "react-hook-form";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// ui components
import {
ToggleSwitch,
PrimaryButton,
SecondaryButton,
Icon,
DangerButton,
Loader,
} from "components/ui";
import { ToggleSwitch, PrimaryButton, SecondaryButton, Icon, DangerButton, Loader } from "components/ui";
import { CustomPopover } from "./popover";
// mobx react lite
import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";
import { IProjectPublishSettings, TProjectPublishViews } from "store/project-publish";
import { IProjectPublishSettings, TProjectPublishViews } from "store/project_publish";
// hooks
import useToast from "hooks/use-toast";
import useProjectDetails from "hooks/use-project-details";
@ -65,8 +58,8 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
let plane_deploy_url = process.env.NEXT_PUBLIC_DEPLOY_URL;
if (typeof window !== 'undefined' && !plane_deploy_url) {
plane_deploy_url= window.location.protocol + "//" + window.location.host + "/spaces";
if (typeof window !== "undefined" && !plane_deploy_url) {
plane_deploy_url = window.location.protocol + "//" + window.location.host + "/spaces";
}
const router = useRouter();
@ -101,10 +94,7 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
// prefill form with the saved settings if the project is already published
useEffect(() => {
if (
projectPublish.projectPublishSettings &&
projectPublish.projectPublishSettings !== "not-initialized"
) {
if (projectPublish.projectPublishSettings && projectPublish.projectPublishSettings !== "not-initialized") {
let userBoards: TProjectPublishViews[] = [];
if (projectPublish.projectPublishSettings?.views) {
@ -143,11 +133,7 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
projectPublish.project_id !== null &&
projectPublish?.projectPublishSettings === "not-initialized"
) {
projectPublish.getProjectSettingsAsync(
workspaceSlug.toString(),
projectPublish.project_id,
null
);
projectPublish.getProjectSettingsAsync(workspaceSlug.toString(), projectPublish.project_id, null);
}
}, [workspaceSlug, projectPublish, projectPublish.projectPublishModal]);
@ -202,12 +188,7 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
setIsUnpublishing(true);
projectPublish
.unPublishProject(
workspaceSlug.toString(),
projectPublish.project_id as string,
publishId,
null
)
.unPublishProject(workspaceSlug.toString(), projectPublish.project_id as string, publishId, null)
.then((res) => {
mutateProjectDetails();
@ -269,11 +250,7 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
// check if an update is required or not
const checkIfUpdateIsRequired = () => {
if (
!projectPublish.projectPublishSettings ||
projectPublish.projectPublishSettings === "not-initialized"
)
return;
if (!projectPublish.projectPublishSettings || projectPublish.projectPublishSettings === "not-initialized") return;
const currentSettings = projectPublish.projectPublishSettings as IProjectPublishSettings;
const newSettings = getValues();
@ -289,8 +266,7 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
let viewCheckFlag = 0;
viewOptions.forEach((option) => {
if (currentSettings.views[option.key] !== newSettings.views.includes(option.key))
viewCheckFlag++;
if (currentSettings.views[option.key] !== newSettings.views.includes(option.key)) viewCheckFlag++;
});
if (viewCheckFlag !== 0) {
@ -416,9 +392,7 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
}}
>
<div className="text-sm">{option.label}</div>
<div
className={`w-[18px] h-[18px] relative flex justify-center items-center`}
>
<div className={`w-[18px] h-[18px] relative flex justify-center items-center`}>
{value.length > 0 && value.includes(option.key) && (
<Icon iconName="done" className="!text-lg" />
)}

View File

@ -11,7 +11,7 @@ import { TwitterPicker } from "react-color";
// headless ui
import { Dialog, Popover, Transition } from "@headlessui/react";
// services
import stateService from "services/state.service";
import stateService from "services/project_state.service";
// hooks
import useToast from "hooks/use-toast";
// ui
@ -131,10 +131,7 @@ export const CreateStateModal: React.FC<Props> = ({ isOpen, projectId, handleClo
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-custom-background-80 px-4 pt-5 pb-4 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-custom-text-100"
>
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-custom-text-100">
Create State
</Dialog.Title>
<div className="mt-2 space-y-3">
@ -215,10 +212,7 @@ export const CreateStateModal: React.FC<Props> = ({ isOpen, projectId, handleClo
name="color"
control={control}
render={({ field: { value, onChange } }) => (
<TwitterPicker
color={value}
onChange={(value) => onChange(value.hex)}
/>
<TwitterPicker color={value} onChange={(value) => onChange(value.hex)} />
)}
/>
</Popover.Panel>

View File

@ -11,7 +11,7 @@ import { TwitterPicker } from "react-color";
// headless ui
import { Popover, Transition } from "@headlessui/react";
// services
import stateService from "services/state.service";
import stateService from "services/project_state.service";
// hooks
import useToast from "hooks/use-toast";
// ui
@ -39,13 +39,7 @@ const defaultValues: Partial<IState> = {
group: "backlog",
};
export const CreateUpdateStateInline: React.FC<Props> = ({
data,
onClose,
selectedGroup,
user,
groupLength,
}) => {
export const CreateUpdateStateInline: React.FC<Props> = ({ data, onClose, selectedGroup, user, groupLength }) => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
@ -153,8 +147,7 @@ export const CreateUpdateStateInline: React.FC<Props> = ({
setToastAlert({
type: "error",
title: "Error!",
message:
"Another state exists with the same name. Please try again with another name.",
message: "Another state exists with the same name. Please try again with another name.",
});
else
setToastAlert({
@ -230,9 +223,7 @@ export const CreateUpdateStateInline: React.FC<Props> = ({
name="group"
control={control}
render={({ field: { value, onChange } }) => (
<Tooltip
tooltipContent={groupLength === 1 ? "Cannot have an empty group." : "Choose State"}
>
<Tooltip tooltipContent={groupLength === 1 ? "Cannot have an empty group." : "Choose State"}>
<div>
<CustomSelect
disabled={groupLength === 1}

View File

@ -9,7 +9,7 @@ import { Dialog, Transition } from "@headlessui/react";
// icons
import { ExclamationTriangleIcon } from "@heroicons/react/24/outline";
// services
import stateServices from "services/state.service";
import stateServices from "services/project_state.service";
// hooks
import useToast from "hooks/use-toast";
// ui
@ -112,24 +112,17 @@ export const DeleteStateModal: React.FC<Props> = ({ isOpen, onClose, data, user
<div className="bg-custom-background-80 px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div className="sm:flex sm:items-start">
<div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10">
<ExclamationTriangleIcon
className="h-6 w-6 text-red-600"
aria-hidden="true"
/>
<ExclamationTriangleIcon className="h-6 w-6 text-red-600" aria-hidden="true" />
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<Dialog.Title
as="h3"
className="text-lg font-medium leading-6 text-custom-text-100"
>
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-custom-text-100">
Delete State
</Dialog.Title>
<div className="mt-2">
<p className="text-sm text-custom-text-200">
Are you sure you want to delete state-{" "}
<span className="font-medium text-custom-text-100">{data?.name}</span>?
All of the data related to the state will be permanently removed. This
action cannot be undone.
<span className="font-medium text-custom-text-100">{data?.name}</span>? All of the data
related to the state will be permanently removed. This action cannot be undone.
</p>
</div>
</div>

View File

@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import { mutate } from "swr";
// services
import stateService from "services/state.service";
import stateService from "services/project_state.service";
// ui
import { Tooltip } from "components/ui";
// icons
@ -58,11 +58,7 @@ export const SingleState: React.FC<Props> = ({
}));
newStatesList = orderArrayBy(newStatesList, "sequence", "ascending");
mutate(
STATES_LIST(projectId as string),
orderStateGroups(groupBy(newStatesList, "group")),
false
);
mutate(STATES_LIST(projectId as string), orderStateGroups(groupBy(newStatesList, "group")), false);
if (currentDefaultState)
stateService
@ -131,11 +127,7 @@ export const SingleState: React.FC<Props> = ({
}));
newStatesList = orderArrayBy(newStatesList, "sequence", "ascending");
mutate(
STATES_LIST(projectId as string),
orderStateGroups(groupBy(newStatesList, "group")),
false
);
mutate(STATES_LIST(projectId as string), orderStateGroups(groupBy(newStatesList, "group")), false);
stateService
.patchState(
@ -216,26 +208,14 @@ export const SingleState: React.FC<Props> = ({
>
{state.default ? (
<Tooltip tooltipContent="Cannot delete the default state.">
<X
className={`h-4 w-4 ${
groupLength < 1 ? "text-custom-sidebar-text-400" : "text-red-500"
}`}
/>
<X className={`h-4 w-4 ${groupLength < 1 ? "text-custom-sidebar-text-400" : "text-red-500"}`} />
</Tooltip>
) : groupLength === 1 ? (
<Tooltip tooltipContent="Cannot have an empty group.">
<X
className={`h-4 w-4 ${
groupLength < 1 ? "text-custom-sidebar-text-400" : "text-red-500"
}`}
/>
<X className={`h-4 w-4 ${groupLength < 1 ? "text-custom-sidebar-text-400" : "text-red-500"}`} />
</Tooltip>
) : (
<X
className={`h-4 w-4 ${
groupLength < 1 ? "text-custom-sidebar-text-400" : "text-red-500"
}`}
/>
<X className={`h-4 w-4 ${groupLength < 1 ? "text-custom-sidebar-text-400" : "text-red-500"}`} />
)}
</button>
</div>

View File

@ -7,7 +7,7 @@ import useSWR from "swr";
// react-hook-form
import { useForm } from "react-hook-form";
// services
import stateService from "services/state.service";
import stateService from "services/project_state.service";
// hooks
import useProjectMembers from "hooks/use-project-members";
// components
@ -20,7 +20,7 @@ import { checkIfArraysHaveSameElements } from "helpers/array.helper";
import { getStatesList } from "helpers/state.helper";
// types
import { IQuery, IView } from "types";
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// fetch-keys
import { PROJECT_ISSUE_LABELS, STATES_LIST } from "constants/fetch-keys";
@ -37,13 +37,7 @@ const defaultValues: Partial<IView> = {
description: "",
};
export const ViewForm: React.FC<Props> = ({
handleFormSubmit,
handleClose,
status,
data,
preLoadedData,
}) => {
export const ViewForm: React.FC<Props> = ({ handleFormSubmit, handleClose, status, data, preLoadedData }) => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
@ -60,9 +54,7 @@ export const ViewForm: React.FC<Props> = ({
const filters = watch("query");
const { data: stateGroups } = useSWR(
workspaceSlug && projectId && (filters?.state ?? []).length > 0
? STATES_LIST(projectId as string)
: null,
workspaceSlug && projectId && (filters?.state ?? []).length > 0 ? STATES_LIST(projectId as string) : null,
workspaceSlug && (filters?.state ?? []).length > 0
? () => stateService.getStates(workspaceSlug as string, projectId as string)
: null
@ -117,9 +109,7 @@ export const ViewForm: React.FC<Props> = ({
return (
<form onSubmit={handleSubmit(handleCreateUpdateView)}>
<div className="space-y-5">
<h3 className="text-lg font-medium leading-6 text-custom-text-100">
{status ? "Update" : "Create"} View
</h3>
<h3 className="text-lg font-medium leading-6 text-custom-text-100">{status ? "Update" : "Create"} View</h3>
<div className="space-y-3">
<div>
<Input
@ -157,10 +147,7 @@ export const ViewForm: React.FC<Props> = ({
const key = option.key as keyof typeof filters;
if (key === "start_date" || key === "target_date") {
const valueExists = checkIfArraysHaveSameElements(
filters?.[key] ?? [],
option.value
);
const valueExists = checkIfArraysHaveSameElements(filters?.[key] ?? [], option.value);
setValue("query", {
...filters,

View File

@ -5,9 +5,9 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import stateService from "services/state.service";
import stateService from "services/project_state.service";
import projectService from "services/project.service";
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// components
import { DateFilterModal } from "components/core";
// ui
@ -32,12 +32,7 @@ type Props = {
height?: "sm" | "md" | "rg" | "lg";
};
export const SelectFilters: React.FC<Props> = ({
filters,
onSelect,
direction = "right",
height = "md",
}) => {
export const SelectFilters: React.FC<Props> = ({ filters, onSelect, direction = "right", height = "md" }) => {
const [isDateFilterModalOpen, setIsDateFilterModalOpen] = useState(false);
const [dateFilterType, setDateFilterType] = useState<{
title: string;
@ -52,9 +47,7 @@ export const SelectFilters: React.FC<Props> = ({
const { data: states } = useSWR(
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
workspaceSlug && projectId
? () => stateService.getStates(workspaceSlug as string, projectId as string)
: null
workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null
);
const statesList = getStatesList(states);

View File

@ -11,7 +11,7 @@ import { mutate } from "swr";
import { useForm } from "react-hook-form";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// fetch keys
import { ISSUE_DETAILS } from "constants/fetch-keys";
@ -75,12 +75,7 @@ export const CreateUpdateLinkForm: React.FC<Props> = (props) => {
if (!data)
await issuesService
.createIssueLink(
workspaceSlug.toString(),
projectId.toString(),
issueId.toString(),
payload
)
.createIssueLink(workspaceSlug.toString(), projectId.toString(), issueId.toString(), payload)
.then(() => {
onSuccess();
mutate(ISSUE_DETAILS(issueId.toString()));
@ -110,20 +105,10 @@ export const CreateUpdateLinkForm: React.FC<Props> = (props) => {
: l
);
mutate(
ISSUE_DETAILS(issueId.toString()),
(prevData) => ({ ...prevData, issue_link: updatedLinks }),
false
);
mutate(ISSUE_DETAILS(issueId.toString()), (prevData) => ({ ...prevData, issue_link: updatedLinks }), false);
await issuesService
.updateIssueLink(
workspaceSlug.toString(),
projectId.toString(),
issueId.toString(),
data!.id,
payload
)
.updateIssueLink(workspaceSlug.toString(), projectId.toString(), issueId.toString(), data!.id, payload)
.then(() => {
onSuccess();
mutate(ISSUE_DETAILS(issueId.toString()));
@ -172,13 +157,7 @@ export const CreateUpdateLinkForm: React.FC<Props> = (props) => {
loading={isSubmitting}
className="w-full !py-2 text-custom-text-300 !text-base flex items-center justify-center"
>
{data
? isSubmitting
? "Updating Link..."
: "Update Link"
: isSubmitting
? "Adding Link..."
: "Add Link"}
{data ? (isSubmitting ? "Updating Link..." : "Update Link") : isSubmitting ? "Adding Link..." : "Add Link"}
</PrimaryButton>
</div>
</form>

View File

@ -11,7 +11,7 @@ import useSWR, { mutate } from "swr";
import { PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useUser from "hooks/use-user";
@ -45,12 +45,7 @@ export const IssueActivity: React.FC<Props> = (props) => {
const { data: issueActivities, mutate: mutateIssueActivity } = useSWR(
workspaceSlug && projectId && issueId ? PROJECT_ISSUES_ACTIVITY(issueId.toString()) : null,
workspaceSlug && projectId && issueId
? () =>
issuesService.getIssueActivities(
workspaceSlug.toString(),
projectId.toString(),
issueId.toString()
)
? () => issuesService.getIssueActivities(workspaceSlug.toString(), projectId.toString(), issueId.toString())
: null
);
@ -58,14 +53,7 @@ export const IssueActivity: React.FC<Props> = (props) => {
if (!workspaceSlug || !projectId || !issueId) return;
await issuesService
.patchIssueComment(
workspaceSlug as string,
projectId as string,
issueId as string,
comment.id,
comment,
user
)
.patchIssueComment(workspaceSlug as string, projectId as string, issueId as string, comment.id, comment, user)
.then(() => mutateIssueActivity());
};
@ -75,13 +63,7 @@ export const IssueActivity: React.FC<Props> = (props) => {
mutateIssueActivity((prevData: any) => prevData?.filter((p: any) => p.id !== commentId), false);
await issuesService
.deleteIssueComment(
workspaceSlug as string,
projectId as string,
issueId as string,
commentId,
user
)
.deleteIssueComment(workspaceSlug as string, projectId as string, issueId as string, commentId, user)
.then(() => mutateIssueActivity());
};
@ -89,13 +71,7 @@ export const IssueActivity: React.FC<Props> = (props) => {
if (!workspaceSlug || !issueDetails) return;
await issuesService
.createIssueComment(
workspaceSlug.toString(),
issueDetails.project,
issueDetails.id,
formData,
user
)
.createIssueComment(workspaceSlug.toString(), issueDetails.project, issueDetails.id, formData, user)
.then(() => {
mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id));
})
@ -118,11 +94,7 @@ export const IssueActivity: React.FC<Props> = (props) => {
<ul role="list" className="-mb-4">
{issueActivities?.map((activityItem, index) => {
// determines what type of action is performed
const message = activityItem.field ? (
<ActivityMessage activity={activityItem} />
) : (
"created the issue."
);
const message = activityItem.field ? <ActivityMessage activity={activityItem} /> : "created the issue.";
if ("field" in activityItem && activityItem.field !== "updated_by") {
return (
@ -141,15 +113,11 @@ export const IssueActivity: React.FC<Props> = (props) => {
<div className="ring-6 flex h-7 w-7 items-center justify-center rounded-full bg-custom-background-80 text-custom-text-200 ring-white">
{activityItem.field ? (
activityItem.new_value === "restore" ? (
<Icon
iconName="history"
className="text-sm text-custom-text-200"
/>
<Icon iconName="history" className="text-sm text-custom-text-200" />
) : (
<ActivityIcon activity={activityItem} />
)
) : activityItem.actor_detail.avatar &&
activityItem.actor_detail.avatar !== "" ? (
) : activityItem.actor_detail.avatar && activityItem.actor_detail.avatar !== "" ? (
<img
src={activityItem.actor_detail.avatar}
alt={activityItem.actor_detail.display_name}
@ -172,13 +140,10 @@ export const IssueActivity: React.FC<Props> = (props) => {
</div>
<div className="min-w-0 flex-1 py-3">
<div className="text-xs text-custom-text-200 break-words">
{activityItem.field === "archived_at" &&
activityItem.new_value !== "restore" ? (
{activityItem.field === "archived_at" && activityItem.new_value !== "restore" ? (
<span className="text-gray font-medium">Plane</span>
) : activityItem.actor_detail.is_bot ? (
<span className="text-gray font-medium">
{activityItem.actor_detail.first_name} Bot
</span>
<span className="text-gray font-medium">{activityItem.actor_detail.first_name} Bot</span>
) : (
<button
type="button"
@ -190,10 +155,7 @@ export const IssueActivity: React.FC<Props> = (props) => {
: activityItem.actor_detail.display_name}
</button>
)}{" "}
{message}{" "}
<span className="whitespace-nowrap">
{timeAgo(activityItem.created_at)}
</span>
{message} <span className="whitespace-nowrap">{timeAgo(activityItem.created_at)}</span>
</div>
</div>
</div>
@ -217,10 +179,7 @@ export const IssueActivity: React.FC<Props> = (props) => {
<AddComment
onSubmit={handleAddComment}
disabled={
!allowed ||
!issueDetails ||
issueDetails.state === "closed" ||
issueDetails.state === "archived"
!allowed || !issueDetails || issueDetails.state === "closed" || issueDetails.state === "archived"
}
/>
</div>

View File

@ -9,7 +9,7 @@ import { useRouter } from "next/router";
import useSWR, { mutate } from "swr";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// react dropzone
import { useDropzone } from "react-dropzone";
@ -61,12 +61,7 @@ export const IssueAttachments: React.FC<Props> = (props) => {
setIsLoading(true);
issuesService
.uploadIssueAttachment(
workspaceSlug as string,
projectId as string,
issueId as string,
formData
)
.uploadIssueAttachment(workspaceSlug as string, projectId as string, issueId as string, formData)
.then((res) => {
mutate<IIssueAttachment[]>(
ISSUE_ATTACHMENTS(issueId as string),
@ -109,12 +104,7 @@ export const IssueAttachments: React.FC<Props> = (props) => {
const { data: attachments } = useSWR<IIssueAttachment[]>(
workspaceSlug && projectId && issueId ? ISSUE_ATTACHMENTS(issueId as string) : null,
workspaceSlug && projectId && issueId
? () =>
issuesService.getIssueAttachment(
workspaceSlug.toString(),
projectId.toString(),
issueId.toString()
)
? () => issuesService.getIssueAttachment(workspaceSlug.toString(), projectId.toString(), issueId.toString())
: null
);

View File

@ -9,7 +9,7 @@ import { useRouter } from "next/router";
import { mutate } from "swr";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// icons
// import { LinkIcon, PlusIcon, PencilIcon, TrashIcon } from "@heroicons/react/24/outline";

View File

@ -11,7 +11,7 @@ import { mutate } from "swr";
import { Control, Controller, useWatch } from "react-hook-form";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useUser from "hooks/use-user";
@ -105,10 +105,7 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
control={control}
name="state"
render={({ field: { value } }) => (
<StateSelect
value={value}
onChange={(val: string) => submitChanges({ state: val })}
/>
<StateSelect value={value} onChange={(val: string) => submitChanges({ state: val })} />
)}
/>
</div>
@ -117,13 +114,7 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
<div className="mb-[6px]">
<div className="border border-custom-border-200 rounded-[4px] p-2 flex justify-between items-center">
<div className="flex items-center gap-1">
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M13.5862 14.5239C13.3459 14.5239 13.1416 14.4398 12.9733 14.2715C12.805 14.1032 12.7209 13.8989 12.7209 13.6585V3.76429C12.7209 3.52391 12.805 3.31958 12.9733 3.15132C13.1416 2.98306 13.3459 2.89893 13.5862 2.89893C13.8266 2.89893 14.031 2.98306 14.1992 3.15132C14.3675 3.31958 14.4516 3.52391 14.4516 3.76429V13.6585C14.4516 13.8989 14.3675 14.1032 14.1992 14.2715C14.031 14.4398 13.8266 14.5239 13.5862 14.5239ZM5.1629 14.5239C5.04676 14.5239 4.93557 14.5018 4.82932 14.4576C4.72308 14.4133 4.63006 14.3513 4.55025 14.2715C4.47045 14.1917 4.40843 14.0986 4.36419 13.9922C4.31996 13.8858 4.29785 13.7746 4.29785 13.6585V11.2643C4.29785 11.0239 4.38198 10.8196 4.55025 10.6513C4.71851 10.4831 4.92283 10.3989 5.16322 10.3989C5.40359 10.3989 5.60791 10.4831 5.77618 10.6513C5.94445 10.8196 6.02859 11.0239 6.02859 11.2643V13.6585C6.02859 13.7746 6.00647 13.8858 5.96223 13.9922C5.91801 14.0986 5.85599 14.1917 5.77618 14.2715C5.69638 14.3513 5.60325 14.4133 5.49678 14.4576C5.39033 14.5018 5.27904 14.5239 5.1629 14.5239ZM9.37473 14.5239C9.13436 14.5239 8.93003 14.4398 8.76176 14.2715C8.59349 14.1032 8.50936 13.8989 8.50936 13.6585V7.5143C8.50936 7.27391 8.59349 7.06958 8.76176 6.90132C8.93003 6.73306 9.13436 6.64893 9.37473 6.64893C9.61511 6.64893 9.81943 6.73306 9.98771 6.90132C10.156 7.06958 10.2401 7.27391 10.2401 7.5143V13.6585C10.2401 13.8989 10.156 14.1032 9.98771 14.2715C9.81943 14.4398 9.61511 14.5239 9.37473 14.5239Z"
fill="#A3A3A3"
@ -137,10 +128,7 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
control={control}
name="priority"
render={({ field: { value } }) => (
<PrioritySelect
value={value}
onChange={(val) => submitChanges({ priority: val })}
/>
<PrioritySelect value={value} onChange={(val) => submitChanges({ priority: val })} />
)}
/>
</div>
@ -157,10 +145,7 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
control={control}
name="assignees_list"
render={({ field: { value } }) => (
<AssigneeSelect
value={value}
onChange={(val: string) => submitChanges({ assignees_list: [val] })}
/>
<AssigneeSelect value={value} onChange={(val: string) => submitChanges({ assignees_list: [val] })} />
)}
/>
</div>
@ -180,10 +165,7 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
control={control}
name="estimate_point"
render={({ field: { value } }) => (
<EstimateSelect
value={value}
onChange={(val) => submitChanges({ estimate_point: val })}
/>
<EstimateSelect value={value} onChange={(val) => submitChanges({ estimate_point: val })} />
)}
/>
</div>
@ -201,10 +183,7 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
control={control}
name="parent"
render={({ field: { value } }) => (
<ParentSelect
value={value}
onChange={(val) => submitChanges({ parent: val })}
/>
<ParentSelect value={value} onChange={(val) => submitChanges({ parent: val })} />
)}
/>
</div>
@ -224,22 +203,16 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
if (!user || !workspaceSlug || !projectId || !issueId) return;
issuesService
.createIssueRelation(
workspaceSlug as string,
projectId as string,
issueId as string,
user,
{
related_list: [
...val.map((issue: any) => ({
issue: issue.blocker_issue_detail.id,
relation_type: "blocked_by" as const,
related_issue: issueId as string,
related_issue_detail: issue.blocker_issue_detail,
})),
],
}
)
.createIssueRelation(workspaceSlug as string, projectId as string, issueId as string, user, {
related_list: [
...val.map((issue: any) => ({
issue: issue.blocker_issue_detail.id,
relation_type: "blocked_by" as const,
related_issue: issueId as string,
related_issue_detail: issue.blocker_issue_detail,
})),
],
})
.then((response) => {
handleMutation({
issue_relations: [
@ -315,22 +288,16 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
if (!user || !workspaceSlug || !projectId || !issueId) return;
issuesService
.createIssueRelation(
workspaceSlug as string,
projectId as string,
issueId as string,
user,
{
related_list: [
...val.map((issue: any) => ({
issue: issue.blocked_issue_detail.id,
relation_type: "blocked_by" as const,
related_issue: issueId as string,
related_issue_detail: issue.blocked_issue_detail,
})),
],
}
)
.createIssueRelation(workspaceSlug as string, projectId as string, issueId as string, user, {
related_list: [
...val.map((issue: any) => ({
issue: issue.blocked_issue_detail.id,
relation_type: "blocked_by" as const,
related_issue: issueId as string,
related_issue_detail: issue.blocked_issue_detail,
})),
],
})
.then((response) => {
handleMutation({
related_issues: [
@ -429,13 +396,8 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
onClick={() => setIsViewAllOpen((prev) => !prev)}
className="w-full flex justify-center items-center gap-1 !py-2"
>
<span className="text-base text-custom-primary-100">
{isViewAllOpen ? "View less" : "View all"}
</span>
<ChevronDown
size={16}
className={`ml-1 text-custom-primary-100 ${isViewAllOpen ? "-rotate-180" : ""}`}
/>
<span className="text-base text-custom-primary-100">{isViewAllOpen ? "View less" : "View all"}</span>
<ChevronDown size={16} className={`ml-1 text-custom-primary-100 ${isViewAllOpen ? "-rotate-180" : ""}`} />
</SecondaryButton>
</div>
</div>

View File

@ -8,7 +8,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// fetch key
import { ISSUE_DETAILS } from "constants/fetch-keys";
@ -37,8 +37,7 @@ export const ParentSelect: React.FC<Props> = (props) => {
const { data: issueDetails } = useSWR(
workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId.toString()) : null,
workspaceSlug && projectId && issueId
? () =>
issuesService.retrieve(workspaceSlug.toString(), projectId.toString(), issueId.toString())
? () => issuesService.retrieve(workspaceSlug.toString(), projectId.toString(), issueId.toString())
: null
);

View File

@ -11,7 +11,7 @@ import useSWR from "swr";
import { ChevronDown } from "lucide-react";
// services
import stateService from "services/state.service";
import stateService from "services/project_state.service";
// fetch key
import { STATES_LIST } from "constants/fetch-keys";
@ -39,9 +39,7 @@ export const StateSelect: React.FC<Props> = (props) => {
const { data: stateGroups } = useSWR(
workspaceSlug && projectId ? STATES_LIST(projectId as string) : null,
workspaceSlug && projectId
? () => stateService.getStates(workspaceSlug as string, projectId as string)
: null
workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null
);
const states = getStatesList(stateGroups);

View File

@ -11,7 +11,7 @@ import useSWR, { mutate } from "swr";
import { X } from "lucide-react";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// fetch key
import { SUB_ISSUES } from "constants/fetch-keys";
@ -41,8 +41,7 @@ export const SubIssueList: React.FC<Props> = (props) => {
const { data: subIssuesResponse } = useSWR(
workspaceSlug && issueDetails ? SUB_ISSUES(issueDetails.id) : null,
workspaceSlug && issueDetails
? () =>
issuesService.subIssues(workspaceSlug as string, issueDetails.project, issueDetails.id)
? () => issuesService.subIssues(workspaceSlug as string, issueDetails.project, issueDetails.id)
: null
);

View File

@ -1,7 +1,7 @@
import useSWR from "swr";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useIssuesView from "hooks/use-issues-view";
// fetch-keys
@ -28,8 +28,7 @@ const useGanttChartIssues = (workspaceSlug: string | undefined, projectId: strin
const { data: ganttIssues, mutate: mutateGanttIssues } = useSWR(
workspaceSlug && projectId ? PROJECT_ISSUES_LIST_WITH_PARAMS(projectId, params) : null,
workspaceSlug && projectId
? () =>
issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params)
? () => issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params)
: null
);

View File

@ -1,7 +1,7 @@
import useSWR from "swr";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
// hooks
import useIssuesView from "hooks/use-issues-view";
// fetch-keys

View File

@ -7,7 +7,7 @@ import useSWR from "swr";
// contexts
import { issueViewContext } from "contexts/issue-view.context";
// services
import issuesService from "services/issues.service";
import issuesService from "services/issue.service";
import cyclesService from "services/cycles.service";
import modulesService from "services/modules.service";
// types
@ -45,19 +45,14 @@ const useCalendarIssuesView = () => {
};
const { data: projectCalendarIssues, mutate: mutateProjectCalendarIssues } = useSWR(
workspaceSlug && projectId ? PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params) : null,
workspaceSlug && projectId
? PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params)
: null,
workspaceSlug && projectId
? () =>
issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params)
? () => issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params)
: null
);
const { data: cycleCalendarIssues, mutate: mutateCycleCalendarIssues } = useSWR(
workspaceSlug && projectId && cycleId
? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params)
: null,
workspaceSlug && projectId && cycleId ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params) : null,
workspaceSlug && projectId && cycleId
? () =>
cyclesService.getCycleIssuesWithParams(
@ -70,9 +65,7 @@ const useCalendarIssuesView = () => {
);
const { data: moduleCalendarIssues, mutate: mutateModuleCalendarIssues } = useSWR(
workspaceSlug && projectId && moduleId
? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params)
: null,
workspaceSlug && projectId && moduleId ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params) : null,
workspaceSlug && projectId && moduleId
? () =>
modulesService.getModuleIssuesWithParams(
@ -87,8 +80,7 @@ const useCalendarIssuesView = () => {
const { data: viewCalendarIssues, mutate: mutateViewCalendarIssues } = useSWR(
workspaceSlug && projectId && viewId && params ? VIEW_ISSUES(viewId.toString(), params) : null,
workspaceSlug && projectId && viewId && params
? () =>
issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params)
? () => issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params)
: null
);

View File

@ -4,7 +4,7 @@ import useSWR from "swr";
import { COMMENT_REACTION_LIST } from "constants/fetch-keys";
// services
import reactionService from "services/reaction.service";
import reactionService from "services/issue_reaction.service";
// helpers
import { groupReactions } from "helpers/emoji.helper";
@ -69,8 +69,7 @@ const useCommentReaction = (
if (!workspaceSlug || !projectId || !commendId) return;
mutateCommentReactions(
(prevData: any) =>
prevData?.filter((r: any) => r.actor !== user?.user?.id || r.reaction !== reaction) || [],
(prevData: any) => prevData?.filter((r: any) => r.actor !== user?.user?.id || r.reaction !== reaction) || [],
false
);

View File

@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// services
import estimatesService from "services/estimates.service";
import estimatesService from "services/project_estimates.service";
// hooks
import useProjectDetails from "hooks/use-project-details";
// helpers

Some files were not shown because too many files have changed in this diff Show More