Merge pull request #1910 from makeplane/develop
promote: develop to stage-release
10
README.md
@ -61,6 +61,16 @@ chmod +x setup.sh
|
||||
|
||||
> If running in a cloud env replace localhost with public facing IP address of the VM
|
||||
|
||||
- Setup Tiptap Pro
|
||||
|
||||
Visit [Tiptap Pro](https://collab.tiptap.dev/pro-extensions) and signup (it is free).
|
||||
|
||||
Create a **`.npmrc`** file, copy the following and replace your registry token generated from Tiptap Pro.
|
||||
|
||||
```
|
||||
@tiptap-pro:registry=https://registry.tiptap.dev/
|
||||
//registry.tiptap.dev/:_authToken=YOUR_REGISTRY_TOKEN
|
||||
```
|
||||
- Run Docker compose up
|
||||
|
||||
```bash
|
||||
|
@ -370,7 +370,7 @@ class UserWorkSpaceIssues(BaseAPIView):
|
||||
)
|
||||
)
|
||||
.filter(**filters)
|
||||
)
|
||||
).distinct()
|
||||
|
||||
# Priority Ordering
|
||||
if order_by_param == "priority" or order_by_param == "-priority":
|
||||
|
@ -994,11 +994,11 @@ class UserWorkspaceDashboardEndpoint(BaseAPIView):
|
||||
|
||||
upcoming_issues = Issue.issue_objects.filter(
|
||||
~Q(state__group__in=["completed", "cancelled"]),
|
||||
target_date__gte=timezone.now(),
|
||||
start_date__gte=timezone.now(),
|
||||
workspace__slug=slug,
|
||||
assignees__in=[request.user],
|
||||
completed_at__isnull=True,
|
||||
).values("id", "name", "workspace__slug", "project_id", "target_date")
|
||||
).values("id", "name", "workspace__slug", "project_id", "start_date")
|
||||
|
||||
return Response(
|
||||
{
|
||||
@ -1083,6 +1083,7 @@ class WorkspaceUserProfileStatsEndpoint(BaseAPIView):
|
||||
.filter(**filters)
|
||||
.values("priority")
|
||||
.annotate(priority_count=Count("priority"))
|
||||
.filter(priority_count__gte=1)
|
||||
.annotate(
|
||||
priority_order=Case(
|
||||
*[
|
||||
|
@ -184,19 +184,24 @@ def track_description(
|
||||
if current_instance.get("description_html") != requested_data.get(
|
||||
"description_html"
|
||||
):
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
issue_id=issue_id,
|
||||
actor=actor,
|
||||
verb="updated",
|
||||
old_value=current_instance.get("description_html"),
|
||||
new_value=requested_data.get("description_html"),
|
||||
field="description",
|
||||
project=project,
|
||||
workspace=project.workspace,
|
||||
comment=f"updated the description to {requested_data.get('description_html')}",
|
||||
)
|
||||
)
|
||||
last_activity = IssueActivity.objects.filter(issue_id=issue_id).order_by("-created_at").first()
|
||||
if(last_activity is not None and last_activity.field == "description" and actor.id == last_activity.actor_id):
|
||||
last_activity.created_at = timezone.now()
|
||||
last_activity.save(update_fields=["created_at"])
|
||||
else:
|
||||
issue_activities.append(
|
||||
IssueActivity(
|
||||
issue_id=issue_id,
|
||||
actor=actor,
|
||||
verb="updated",
|
||||
old_value=current_instance.get("description_html"),
|
||||
new_value=requested_data.get("description_html"),
|
||||
field="description",
|
||||
project=project,
|
||||
workspace=project.workspace,
|
||||
comment=f"updated the description to {requested_data.get('description_html')}",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# Track changes in issue target date
|
||||
|
@ -227,6 +227,11 @@ class Migration(migrations.Migration):
|
||||
'unique_together': {('issue', 'actor')},
|
||||
},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='modulelink',
|
||||
name='title',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.RunPython(generate_display_name),
|
||||
migrations.RunPython(rectify_field_issue_activity),
|
||||
migrations.RunPython(update_assignee_issue_activity),
|
||||
|
@ -98,7 +98,7 @@ class ModuleIssue(ProjectBaseModel):
|
||||
|
||||
|
||||
class ModuleLink(ProjectBaseModel):
|
||||
title = models.CharField(max_length=255, null=True)
|
||||
title = models.CharField(max_length=255, blank=True, null=True)
|
||||
url = models.URLField()
|
||||
module = models.ForeignKey(
|
||||
Module, on_delete=models.CASCADE, related_name="link_module"
|
||||
|
@ -1,3 +1,8 @@
|
||||
// ui
|
||||
import { ProfileEmptyState } from "components/ui";
|
||||
// image
|
||||
import emptyUsers from "public/empty-state/empty_users.svg";
|
||||
|
||||
type Props = {
|
||||
users: {
|
||||
avatar: string | null;
|
||||
@ -8,10 +13,16 @@ type Props = {
|
||||
id: string;
|
||||
}[];
|
||||
title: string;
|
||||
emptyStateMessage: string;
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export const AnalyticsLeaderboard: React.FC<Props> = ({ users, title, workspaceSlug }) => (
|
||||
export const AnalyticsLeaderboard: React.FC<Props> = ({
|
||||
users,
|
||||
title,
|
||||
emptyStateMessage,
|
||||
workspaceSlug,
|
||||
}) => (
|
||||
<div className="p-3 border border-custom-border-200 rounded-[10px]">
|
||||
<h6 className="text-base font-medium">{title}</h6>
|
||||
{users.length > 0 ? (
|
||||
@ -47,7 +58,9 @@ export const AnalyticsLeaderboard: React.FC<Props> = ({ users, title, workspaceS
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-custom-text-200 text-center text-sm py-8">No matching data found.</div>
|
||||
<div className="px-7 py-4">
|
||||
<ProfileEmptyState title="No Data yet" description={emptyStateMessage} image={emptyUsers} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -63,6 +63,7 @@ export const ScopeAndDemand: React.FC<Props> = ({ fullScreen = true }) => {
|
||||
id: user?.created_by__id,
|
||||
}))}
|
||||
title="Most issues created"
|
||||
emptyStateMessage="Co-workers and the number issues created by them appears here."
|
||||
workspaceSlug={workspaceSlug?.toString() ?? ""}
|
||||
/>
|
||||
<AnalyticsLeaderboard
|
||||
@ -75,6 +76,7 @@ export const ScopeAndDemand: React.FC<Props> = ({ fullScreen = true }) => {
|
||||
id: user?.assignees__id,
|
||||
}))}
|
||||
title="Most issues closed"
|
||||
emptyStateMessage="Co-workers and the number issues closed by them appears here."
|
||||
workspaceSlug={workspaceSlug?.toString() ?? ""}
|
||||
/>
|
||||
<div className={fullScreen ? "md:col-span-2" : ""}>
|
||||
|
@ -1,5 +1,7 @@
|
||||
// ui
|
||||
import { BarGraph } from "components/ui";
|
||||
import { BarGraph, ProfileEmptyState } from "components/ui";
|
||||
// image
|
||||
import emptyBarGraph from "public/empty-state/empty_bar_graph.svg";
|
||||
// types
|
||||
import { IDefaultAnalyticsResponse } from "types";
|
||||
|
||||
@ -70,8 +72,12 @@ export const AnalyticsScope: React.FC<Props> = ({ defaultAnalytics }) => (
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div className="text-custom-text-200 text-center text-sm py-8">
|
||||
No matching data found.
|
||||
<div className="px-7 py-4">
|
||||
<ProfileEmptyState
|
||||
title="No Data yet"
|
||||
description="Analysis of pending issues by co-workers appears here."
|
||||
image={emptyBarGraph}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -1,5 +1,7 @@
|
||||
// ui
|
||||
import { LineGraph } from "components/ui";
|
||||
import { LineGraph, ProfileEmptyState } from "components/ui";
|
||||
// image
|
||||
import emptyGraph from "public/empty-state/empty_graph.svg";
|
||||
// types
|
||||
import { IDefaultAnalyticsResponse } from "types";
|
||||
// constants
|
||||
@ -48,7 +50,13 @@ export const AnalyticsYearWiseIssues: React.FC<Props> = ({ defaultAnalytics }) =
|
||||
enableArea
|
||||
/>
|
||||
) : (
|
||||
<div className="text-custom-text-200 text-center text-sm py-8">No matching data found.</div>
|
||||
<div className="px-7 py-4">
|
||||
<ProfileEmptyState
|
||||
title="No Data yet"
|
||||
description="Close issues to view analysis of the same in the form of a graph."
|
||||
image={emptyGraph}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -9,12 +9,18 @@ import userService from "services/user.service";
|
||||
import useUser from "hooks/use-user";
|
||||
// helper
|
||||
import { unsetCustomCssVariables } from "helpers/theme.helper";
|
||||
// mobx react lite
|
||||
import { observer } from "mobx-react-lite";
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
|
||||
type Props = {
|
||||
setIsPaletteOpen: Dispatch<SetStateAction<boolean>>;
|
||||
};
|
||||
|
||||
export const ChangeInterfaceTheme: React.FC<Props> = ({ setIsPaletteOpen }) => {
|
||||
export const ChangeInterfaceTheme: React.FC<Props> = observer(({ setIsPaletteOpen }) => {
|
||||
const store: any = useMobxStore();
|
||||
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
const { setTheme } = useTheme();
|
||||
@ -23,29 +29,11 @@ export const ChangeInterfaceTheme: React.FC<Props> = ({ setIsPaletteOpen }) => {
|
||||
|
||||
const updateUserTheme = (newTheme: string) => {
|
||||
if (!user) return;
|
||||
|
||||
unsetCustomCssVariables();
|
||||
|
||||
setTheme(newTheme);
|
||||
|
||||
mutateUser((prevData: any) => {
|
||||
if (!prevData) return prevData;
|
||||
|
||||
return {
|
||||
...prevData,
|
||||
theme: {
|
||||
...prevData?.theme,
|
||||
theme: newTheme,
|
||||
},
|
||||
};
|
||||
}, false);
|
||||
|
||||
userService.updateUser({
|
||||
theme: {
|
||||
...user.theme,
|
||||
theme: newTheme,
|
||||
},
|
||||
});
|
||||
return store.user
|
||||
.updateCurrentUserSettings({ theme: { ...user.theme, theme: newTheme } })
|
||||
.then((response: any) => response)
|
||||
.catch((error: any) => error);
|
||||
};
|
||||
|
||||
// useEffect only runs on the client, so now we can safely show the UI
|
||||
@ -74,4 +62,4 @@ export const ChangeInterfaceTheme: React.FC<Props> = ({ setIsPaletteOpen }) => {
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -145,7 +145,7 @@ export const GptAssistantModal: React.FC<Props> = ({
|
||||
}`}
|
||||
>
|
||||
{((content && content !== "") || (htmlContent && htmlContent !== "<p></p>")) && (
|
||||
<div id="tiptap-container" className="text-sm">
|
||||
<div className="text-sm">
|
||||
Content:
|
||||
<TiptapEditor
|
||||
value={htmlContent ?? `<p>${content}</p>`}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
// react-hook-form
|
||||
import { useForm } from "react-hook-form";
|
||||
@ -7,12 +7,15 @@ import { Dialog, Transition } from "@headlessui/react";
|
||||
// ui
|
||||
import { Input, PrimaryButton, SecondaryButton } from "components/ui";
|
||||
// types
|
||||
import type { IIssueLink, ModuleLink } from "types";
|
||||
import type { IIssueLink, linkDetails, ModuleLink } from "types";
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean;
|
||||
handleClose: () => void;
|
||||
onFormSubmit: (formData: IIssueLink | ModuleLink) => Promise<void>;
|
||||
data?: linkDetails | null;
|
||||
status: boolean;
|
||||
createIssueLink: (formData: IIssueLink | ModuleLink) => Promise<void>;
|
||||
updateIssueLink: (formData: IIssueLink | ModuleLink, linkId: string) => Promise<void>;
|
||||
};
|
||||
|
||||
const defaultValues: IIssueLink | ModuleLink = {
|
||||
@ -20,7 +23,14 @@ const defaultValues: IIssueLink | ModuleLink = {
|
||||
url: "",
|
||||
};
|
||||
|
||||
export const LinkModal: React.FC<Props> = ({ isOpen, handleClose, onFormSubmit }) => {
|
||||
export const LinkModal: React.FC<Props> = ({
|
||||
isOpen,
|
||||
handleClose,
|
||||
createIssueLink,
|
||||
updateIssueLink,
|
||||
status,
|
||||
data,
|
||||
}) => {
|
||||
const {
|
||||
register,
|
||||
formState: { errors, isSubmitting },
|
||||
@ -30,11 +40,6 @@ export const LinkModal: React.FC<Props> = ({ isOpen, handleClose, onFormSubmit }
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
const onSubmit = async (formData: IIssueLink | ModuleLink) => {
|
||||
await onFormSubmit({ title: formData.title, url: formData.url });
|
||||
onClose();
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
handleClose();
|
||||
const timeout = setTimeout(() => {
|
||||
@ -43,6 +48,27 @@ export const LinkModal: React.FC<Props> = ({ isOpen, handleClose, onFormSubmit }
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const handleFormSubmit = async (formData: IIssueLink | ModuleLink) => {
|
||||
if (!data) await createIssueLink({ title: formData.title, url: formData.url });
|
||||
else await updateIssueLink({ title: formData.title, url: formData.url }, data.id);
|
||||
onClose();
|
||||
};
|
||||
|
||||
const handleCreateUpdatePage = async (formData: IIssueLink | ModuleLink) => {
|
||||
await handleFormSubmit(formData);
|
||||
|
||||
reset({
|
||||
...defaultValues,
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
reset({
|
||||
...defaultValues,
|
||||
...data,
|
||||
});
|
||||
}, [data, reset]);
|
||||
|
||||
return (
|
||||
<Transition.Root show={isOpen} as={React.Fragment}>
|
||||
<Dialog as="div" className="relative z-20" onClose={onClose}>
|
||||
@ -70,14 +96,14 @@ export const LinkModal: React.FC<Props> = ({ isOpen, handleClose, onFormSubmit }
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-custom-background-100 border border-custom-border-200 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)}>
|
||||
<form onSubmit={handleSubmit(handleCreateUpdatePage)}>
|
||||
<div>
|
||||
<div className="space-y-5">
|
||||
<Dialog.Title
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-custom-text-100"
|
||||
>
|
||||
Add Link
|
||||
{status ? "Update Link" : "Add Link"}
|
||||
</Dialog.Title>
|
||||
<div className="mt-2 space-y-3">
|
||||
<div>
|
||||
@ -113,7 +139,13 @@ export const LinkModal: React.FC<Props> = ({ isOpen, handleClose, onFormSubmit }
|
||||
<div className="mt-5 flex justify-end gap-2">
|
||||
<SecondaryButton onClick={onClose}>Cancel</SecondaryButton>
|
||||
<PrimaryButton type="submit" loading={isSubmitting}>
|
||||
{isSubmitting ? "Adding Link..." : "Add Link"}
|
||||
{status
|
||||
? isSubmitting
|
||||
? "Updating Link..."
|
||||
: "Update Link"
|
||||
: isSubmitting
|
||||
? "Adding Link..."
|
||||
: "Add Link"}
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -1,25 +1,24 @@
|
||||
// icons
|
||||
import { ArrowTopRightOnSquareIcon, LinkIcon, TrashIcon } from "@heroicons/react/24/outline";
|
||||
import { Icon } from "components/ui";
|
||||
// helpers
|
||||
import { timeAgo } from "helpers/date-time.helper";
|
||||
// types
|
||||
import { IUserLite, UserAuth } from "types";
|
||||
import { linkDetails, UserAuth } from "types";
|
||||
|
||||
type Props = {
|
||||
links: {
|
||||
id: string;
|
||||
created_at: Date;
|
||||
created_by: string;
|
||||
created_by_detail: IUserLite;
|
||||
metadata: any;
|
||||
title: string;
|
||||
url: string;
|
||||
}[];
|
||||
links: linkDetails[];
|
||||
handleDeleteLink: (linkId: string) => void;
|
||||
handleEditLink: (link: linkDetails) => void;
|
||||
userAuth: UserAuth;
|
||||
};
|
||||
|
||||
export const LinksList: React.FC<Props> = ({ links, handleDeleteLink, userAuth }) => {
|
||||
export const LinksList: React.FC<Props> = ({
|
||||
links,
|
||||
handleDeleteLink,
|
||||
handleEditLink,
|
||||
userAuth,
|
||||
}) => {
|
||||
const isNotAllowed = userAuth.isGuest || userAuth.isViewer;
|
||||
|
||||
return (
|
||||
@ -28,6 +27,13 @@ export const LinksList: React.FC<Props> = ({ links, handleDeleteLink, userAuth }
|
||||
<div key={link.id} className="relative">
|
||||
{!isNotAllowed && (
|
||||
<div className="absolute top-1.5 right-1.5 z-[1] flex items-center gap-1">
|
||||
<button
|
||||
type="button"
|
||||
className="grid h-7 w-7 place-items-center rounded bg-custom-background-90 p-1 outline-none hover:bg-custom-background-80"
|
||||
onClick={() => handleEditLink(link)}
|
||||
>
|
||||
<Icon iconName="edit" className="text-custom-text-200" />
|
||||
</button>
|
||||
<a
|
||||
href={link.url}
|
||||
target="_blank"
|
||||
|
@ -45,18 +45,26 @@ export const ThemeSwitch: React.FC<Props> = observer(
|
||||
currentThemeObj ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="h-full w-1/2 rounded-l-full"
|
||||
className="border-1 relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border"
|
||||
style={{
|
||||
background: currentThemeObj.icon.color1,
|
||||
borderColor: currentThemeObj.icon.border,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="h-full w-1/2 rounded-r-full border-l"
|
||||
style={{
|
||||
borderLeftColor: currentThemeObj.icon.border,
|
||||
background: currentThemeObj.icon.color2,
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<div
|
||||
className="h-full w-1/2 rounded-l-full"
|
||||
style={{
|
||||
background: currentThemeObj.icon.color1,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="h-full w-1/2 rounded-r-full border-l"
|
||||
style={{
|
||||
borderLeftColor: currentThemeObj.icon.border,
|
||||
background: currentThemeObj.icon.color2,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{currentThemeObj.label}
|
||||
</div>
|
||||
) : (
|
||||
"Select your theme"
|
||||
@ -98,18 +106,26 @@ export const ThemeSwitch: React.FC<Props> = observer(
|
||||
<CustomSelect.Option key={value} value={{ value, type }}>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="h-full w-1/2 rounded-l-full"
|
||||
className="border-1 relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border"
|
||||
style={{
|
||||
background: icon.color1,
|
||||
borderColor: icon.border,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="h-full w-1/2 rounded-r-full border-l"
|
||||
style={{
|
||||
borderLeftColor: icon.border,
|
||||
background: icon.color2,
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<div
|
||||
className="h-full w-1/2 rounded-l-full"
|
||||
style={{
|
||||
background: icon.color1,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="h-full w-1/2 rounded-r-full border-l"
|
||||
style={{
|
||||
borderLeftColor: icon.border,
|
||||
background: icon.color2,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{label}
|
||||
</div>
|
||||
</CustomSelect.Option>
|
||||
))}
|
||||
|
@ -88,6 +88,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
||||
const [contextMenu, setContextMenu] = useState(false);
|
||||
const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 });
|
||||
const [isMenuActive, setIsMenuActive] = useState(false);
|
||||
const [isDropdownActive, setIsDropdownActive] = useState(false);
|
||||
|
||||
const actionSectionRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
@ -245,7 +246,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
||||
setContextMenuPosition({ x: e.pageX, y: e.pageY });
|
||||
}}
|
||||
>
|
||||
<div className="group/card relative select-none p-3.5">
|
||||
<div className="flex flex-col justify-between gap-1.5 group/card relative select-none px-3.5 py-3 h-[118px]">
|
||||
{!isNotAllowed && (
|
||||
<div
|
||||
ref={actionSectionRef}
|
||||
@ -295,16 +296,20 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
||||
</div>
|
||||
)}
|
||||
<Link href={`/${workspaceSlug}/projects/${issue.project}/issues/${issue.id}`}>
|
||||
<a>
|
||||
<a className="flex flex-col gap-1.5">
|
||||
{properties.key && (
|
||||
<div className="mb-2.5 text-xs font-medium text-custom-text-200">
|
||||
<div className="text-xs font-medium text-custom-text-200">
|
||||
{issue.project_detail.identifier}-{issue.sequence_id}
|
||||
</div>
|
||||
)}
|
||||
<h5 className="text-sm break-words line-clamp-2">{issue.name}</h5>
|
||||
</a>
|
||||
</Link>
|
||||
<div className="mt-2.5 flex overflow-x-scroll items-center gap-2 text-xs">
|
||||
<div
|
||||
className={`flex items-center gap-2 text-xs ${
|
||||
isDropdownActive ? "" : "overflow-x-scroll"
|
||||
}`}
|
||||
>
|
||||
{properties.priority && (
|
||||
<ViewPrioritySelect
|
||||
issue={issue}
|
||||
@ -327,6 +332,8 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
||||
<ViewStartDateSelect
|
||||
issue={issue}
|
||||
partialUpdateIssue={partialUpdateIssue}
|
||||
handleOnOpen={() => setIsDropdownActive(true)}
|
||||
handleOnClose={() => setIsDropdownActive(false)}
|
||||
user={user}
|
||||
isNotAllowed={isNotAllowed}
|
||||
/>
|
||||
@ -335,6 +342,8 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
||||
<ViewDueDateSelect
|
||||
issue={issue}
|
||||
partialUpdateIssue={partialUpdateIssue}
|
||||
handleOnOpen={() => setIsDropdownActive(true)}
|
||||
handleOnClose={() => setIsDropdownActive(false)}
|
||||
user={user}
|
||||
isNotAllowed={isNotAllowed}
|
||||
/>
|
||||
|
@ -45,7 +45,6 @@ type TSingleStatProps = {
|
||||
handleDeleteCycle: () => void;
|
||||
handleAddToFavorites: () => void;
|
||||
handleRemoveFromFavorites: () => void;
|
||||
isCompleted?: boolean;
|
||||
};
|
||||
|
||||
const stateGroups = [
|
||||
@ -82,7 +81,6 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
||||
handleDeleteCycle,
|
||||
handleAddToFavorites,
|
||||
handleRemoveFromFavorites,
|
||||
isCompleted = false,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
@ -90,6 +88,7 @@ export const SingleCycleCard: React.FC<TSingleStatProps> = ({
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
const cycleStatus = getDateRangeStatus(cycle.start_date, cycle.end_date);
|
||||
const isCompleted = cycleStatus === "completed";
|
||||
const endDate = new Date(cycle.end_date ?? "");
|
||||
const startDate = new Date(cycle.start_date ?? "");
|
||||
|
||||
|
@ -34,7 +34,6 @@ type TSingleStatProps = {
|
||||
handleDeleteCycle: () => void;
|
||||
handleAddToFavorites: () => void;
|
||||
handleRemoveFromFavorites: () => void;
|
||||
isCompleted?: boolean;
|
||||
};
|
||||
|
||||
const stateGroups = [
|
||||
@ -113,7 +112,6 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
||||
handleDeleteCycle,
|
||||
handleAddToFavorites,
|
||||
handleRemoveFromFavorites,
|
||||
isCompleted = false,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
@ -121,6 +119,7 @@ export const SingleCycleList: React.FC<TSingleStatProps> = ({
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
const cycleStatus = getDateRangeStatus(cycle.start_date, cycle.end_date);
|
||||
const isCompleted = cycleStatus === "completed";
|
||||
const endDate = new Date(cycle.end_date ?? "");
|
||||
const startDate = new Date(cycle.start_date ?? "");
|
||||
|
||||
|
@ -134,7 +134,9 @@ export const IssueActivitySection: React.FC<Props> = ({ issueId, user }) => {
|
||||
<div
|
||||
className={`grid h-7 w-7 place-items-center rounded-full border-2 border-white bg-gray-700 text-xs text-white`}
|
||||
>
|
||||
{activityItem.actor_detail.display_name.charAt(0)}
|
||||
{activityItem.actor_detail.is_bot
|
||||
? activityItem.actor_detail.first_name.charAt(0)
|
||||
: activityItem.actor_detail.display_name.charAt(0)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -153,7 +155,9 @@ export const IssueActivitySection: React.FC<Props> = ({ issueId, user }) => {
|
||||
) : (
|
||||
<Link href={`/${workspaceSlug}/profile/${activityItem.actor_detail.id}`}>
|
||||
<a className="text-gray font-medium">
|
||||
{activityItem.actor_detail.display_name}
|
||||
{activityItem.actor_detail.is_bot
|
||||
? activityItem.actor_detail.first_name
|
||||
: activityItem.actor_detail.display_name}
|
||||
</a>
|
||||
</Link>
|
||||
)}{" "}
|
||||
|
@ -87,7 +87,7 @@ export const AddComment: React.FC<Props> = ({ issueId, user, disabled = false })
|
||||
return (
|
||||
<div>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div id="tiptap-container" className="issue-comments-section">
|
||||
<div className="issue-comments-section">
|
||||
<Controller
|
||||
name="comment_html"
|
||||
control={control}
|
||||
@ -101,7 +101,7 @@ export const AddComment: React.FC<Props> = ({ issueId, user, disabled = false })
|
||||
? watch("comment_html")
|
||||
: value
|
||||
}
|
||||
customClassName="p-3 min-h-[50px]"
|
||||
customClassName="p-3 min-h-[50px] shadow-sm"
|
||||
debouncedUpdatesEnabled={false}
|
||||
onChange={(comment_json: Object, comment_html: string) => {
|
||||
onChange(comment_html);
|
||||
|
@ -65,7 +65,11 @@ export const CommentCard: React.FC<Props> = ({ comment, onSubmit, handleCommentD
|
||||
{comment.actor_detail.avatar && comment.actor_detail.avatar !== "" ? (
|
||||
<img
|
||||
src={comment.actor_detail.avatar}
|
||||
alt={comment.actor_detail.display_name}
|
||||
alt={
|
||||
comment.actor_detail.is_bot
|
||||
? comment.actor_detail.first_name + " Bot"
|
||||
: comment.actor_detail.display_name
|
||||
}
|
||||
height={30}
|
||||
width={30}
|
||||
className="grid h-7 w-7 place-items-center rounded-full border-2 border-custom-border-200"
|
||||
@ -74,7 +78,9 @@ export const CommentCard: React.FC<Props> = ({ comment, onSubmit, handleCommentD
|
||||
<div
|
||||
className={`grid h-7 w-7 place-items-center rounded-full border-2 border-white bg-gray-500 text-white`}
|
||||
>
|
||||
{comment.actor_detail.display_name.charAt(0)}
|
||||
{comment.actor_detail.is_bot
|
||||
? comment.actor_detail.first_name.charAt(0)
|
||||
: comment.actor_detail.display_name.charAt(0)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -101,12 +107,12 @@ export const CommentCard: React.FC<Props> = ({ comment, onSubmit, handleCommentD
|
||||
className={`flex-col gap-2 ${isEditing ? "flex" : "hidden"}`}
|
||||
onSubmit={handleSubmit(onEnter)}
|
||||
>
|
||||
<div id="tiptap-container">
|
||||
<div>
|
||||
<TiptapEditor
|
||||
ref={editorRef}
|
||||
value={watch("comment_html")}
|
||||
debouncedUpdatesEnabled={false}
|
||||
customClassName="min-h-[50px] p-3"
|
||||
customClassName="min-h-[50px] p-3 shadow-sm"
|
||||
onChange={(comment_json: Object, comment_html: string) => {
|
||||
setValue("comment_json", comment_json);
|
||||
setValue("comment_html", comment_html);
|
||||
|
@ -112,8 +112,9 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
||||
{characterLimit && (
|
||||
<div className="pointer-events-none absolute bottom-1 right-1 z-[2] rounded bg-custom-background-100 text-custom-text-200 p-0.5 text-xs">
|
||||
<span
|
||||
className={`${watch("name").length === 0 || watch("name").length > 255 ? "text-red-500" : ""
|
||||
}`}
|
||||
className={`${
|
||||
watch("name").length === 0 || watch("name").length > 255 ? "text-red-500" : ""
|
||||
}`}
|
||||
>
|
||||
{watch("name").length}
|
||||
</span>
|
||||
@ -122,7 +123,7 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
||||
)}
|
||||
</div>
|
||||
<span>{errors.name ? errors.name.message : null}</span>
|
||||
<div id="tiptap-container" className="relative">
|
||||
<div className="relative">
|
||||
<Controller
|
||||
name="description_html"
|
||||
control={control}
|
||||
@ -133,14 +134,14 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
||||
<Tiptap
|
||||
value={
|
||||
!value ||
|
||||
value === "" ||
|
||||
(typeof value === "object" && Object.keys(value).length === 0)
|
||||
value === "" ||
|
||||
(typeof value === "object" && Object.keys(value).length === 0)
|
||||
? watch("description_html")
|
||||
: value
|
||||
}
|
||||
debouncedUpdatesEnabled={true}
|
||||
setIsSubmitting={setIsSubmitting}
|
||||
customClassName="min-h-[150px]"
|
||||
customClassName="min-h-[150px] shadow-sm"
|
||||
editorContentCustomClassNames="pb-9"
|
||||
onChange={(description: Object, description_html: string) => {
|
||||
setIsSubmitting("submitting");
|
||||
@ -154,8 +155,12 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<div className={`absolute right-5 bottom-5 text-xs text-custom-text-200 border border-custom-border-400 rounded-xl w-[6.5rem] py-1 z-10 flex items-center justify-center ${isSubmitting === 'saved' ? 'fadeOut' : 'fadeIn'}`}>
|
||||
{isSubmitting === 'submitting' ? 'Saving...' : 'Saved'}
|
||||
<div
|
||||
className={`absolute right-5 bottom-5 text-xs text-custom-text-200 border border-custom-border-400 rounded-xl w-[6.5rem] py-1 z-10 flex items-center justify-center ${
|
||||
isSubmitting === "saved" ? "fadeOut" : "fadeIn"
|
||||
}`}
|
||||
>
|
||||
{isSubmitting === "submitting" ? "Saving..." : "Saved"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -333,7 +333,7 @@ export const IssueForm: FC<IssueFormProps> = ({
|
||||
</div>
|
||||
)}
|
||||
{(fieldsToShow.includes("all") || fieldsToShow.includes("description")) && (
|
||||
<div id="tiptap-container" className="relative">
|
||||
<div className="relative">
|
||||
<div className="flex justify-end">
|
||||
{issueName && issueName !== "" && (
|
||||
<button
|
||||
|
@ -5,9 +5,7 @@ import useSWR from "swr";
|
||||
// services
|
||||
import projectServices from "services/project.service";
|
||||
// ui
|
||||
import { AssigneesList, Avatar, CustomSearchSelect } from "components/ui";
|
||||
// icons
|
||||
import { UserGroupIcon } from "@heroicons/react/24/outline";
|
||||
import { AssigneesList, Avatar, CustomSearchSelect, Icon } from "components/ui";
|
||||
// fetch-keys
|
||||
import { PROJECT_MEMBERS } from "constants/fetch-keys";
|
||||
|
||||
@ -44,15 +42,15 @@ export const IssueAssigneeSelect: React.FC<Props> = ({ projectId, value = [], on
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
options={options}
|
||||
label={
|
||||
<div className="flex items-center gap-2 text-custom-text-200">
|
||||
customButton={
|
||||
<div className="flex items-center gap-2 cursor-pointer text-xs text-custom-text-200">
|
||||
{value && value.length > 0 && Array.isArray(value) ? (
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<div className="-my-0.5 flex items-center justify-center gap-2">
|
||||
<AssigneesList userIds={value} length={3} showLength={true} />
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<UserGroupIcon className="h-4 w-4 text-custom-text-200" />
|
||||
<div className="flex items-center justify-center gap-2 px-1.5 py-1 rounded shadow-sm border border-custom-border-300 hover:bg-custom-background-80">
|
||||
<Icon iconName="person" className="!text-base !leading-4" />
|
||||
<span className="text-custom-text-200">Assignee</span>
|
||||
</div>
|
||||
)}
|
||||
|
@ -20,7 +20,7 @@ export const IssueDateSelect: React.FC<Props> = ({ label, maxDate, minDate, onCh
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Popover.Button className="flex cursor-pointer items-center rounded-md border border-custom-border-200 text-xs shadow-sm duration-200">
|
||||
<span className="flex items-center justify-center gap-2 px-2 py-1 text-xs text-custom-text-200">
|
||||
<span className="flex items-center justify-center gap-2 px-2 py-1 text-xs text-custom-text-200 hover:bg-custom-background-80">
|
||||
{value ? (
|
||||
<>
|
||||
<span className="text-custom-text-100">{renderShortDateWithYearFormat(value)}</span>
|
||||
|
@ -59,17 +59,17 @@ export const IssueLabelSelect: React.FC<Props> = ({ setIsOpen, value, onChange,
|
||||
>
|
||||
{({ open }: any) => (
|
||||
<>
|
||||
<Combobox.Button className="flex cursor-pointer items-center rounded-md border border-custom-border-200 text-xs shadow-sm duration-200 hover:bg-custom-background-80">
|
||||
<Combobox.Button className="flex items-center gap-2 cursor-pointer text-xs text-custom-text-200">
|
||||
{value && value.length > 0 ? (
|
||||
<span className="flex items-center justify-center gap-2 px-3 py-1 text-xs">
|
||||
<span className="flex items-center justify-center gap-2 text-xs">
|
||||
<IssueLabelsList
|
||||
labels={value.map((v) => issueLabels?.find((l) => l.id === v)?.color) ?? []}
|
||||
labels={value.map((v) => issueLabels?.find((l) => l.id === v)) ?? []}
|
||||
length={3}
|
||||
showLength={true}
|
||||
/>
|
||||
</span>
|
||||
) : (
|
||||
<span className="flex items-center justify-center gap-2 px-2.5 py-1 text-xs">
|
||||
<span className="flex items-center justify-center gap-2 px-2 py-1 text-xs rounded shadow-sm border border-custom-border-300 hover:bg-custom-background-80">
|
||||
<TagIcon className="h-3.5 w-3.5 text-custom-text-200" />
|
||||
<span className=" text-custom-text-200">Label</span>
|
||||
</span>
|
||||
|
@ -37,7 +37,7 @@ import { LinkIcon, CalendarDaysIcon, TrashIcon, PlusIcon } from "@heroicons/reac
|
||||
// helpers
|
||||
import { copyTextToClipboard } from "helpers/string.helper";
|
||||
// types
|
||||
import type { ICycle, IIssue, IIssueLink, IModule } from "types";
|
||||
import type { ICycle, IIssue, IIssueLink, linkDetails, IModule } from "types";
|
||||
// fetch-keys
|
||||
import { ISSUE_DETAILS } from "constants/fetch-keys";
|
||||
|
||||
@ -77,6 +77,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
}) => {
|
||||
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
|
||||
const [linkModal, setLinkModal] = useState(false);
|
||||
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<linkDetails | null>(null);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, issueId } = router.query;
|
||||
@ -156,6 +157,43 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
});
|
||||
};
|
||||
|
||||
const handleUpdateLink = async (formData: IIssueLink, linkId: string) => {
|
||||
if (!workspaceSlug || !projectId || !issueDetail) return;
|
||||
|
||||
const payload = { metadata: {}, ...formData };
|
||||
|
||||
const updatedLinks = issueDetail.issue_link.map((l) =>
|
||||
l.id === linkId
|
||||
? {
|
||||
...l,
|
||||
title: formData.title,
|
||||
url: formData.url,
|
||||
}
|
||||
: l
|
||||
);
|
||||
|
||||
mutate<IIssue>(
|
||||
ISSUE_DETAILS(issueDetail.id),
|
||||
(prevData) => ({ ...(prevData as IIssue), issue_link: updatedLinks }),
|
||||
false
|
||||
);
|
||||
|
||||
await issuesService
|
||||
.updateIssueLink(
|
||||
workspaceSlug as string,
|
||||
projectId as string,
|
||||
issueDetail.id,
|
||||
linkId,
|
||||
payload
|
||||
)
|
||||
.then((res) => {
|
||||
mutate(ISSUE_DETAILS(issueDetail.id));
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
const handleDeleteLink = async (linkId: string) => {
|
||||
if (!workspaceSlug || !projectId || !issueDetail) return;
|
||||
|
||||
@ -220,14 +258,25 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
const maxDate = targetDate ? new Date(targetDate) : null;
|
||||
maxDate?.setDate(maxDate.getDate());
|
||||
|
||||
const handleEditLink = (link: linkDetails) => {
|
||||
setSelectedLinkToUpdate(link);
|
||||
setLinkModal(true);
|
||||
};
|
||||
|
||||
const isNotAllowed = memberRole.isGuest || memberRole.isViewer;
|
||||
|
||||
return (
|
||||
<>
|
||||
<LinkModal
|
||||
isOpen={linkModal}
|
||||
handleClose={() => setLinkModal(false)}
|
||||
onFormSubmit={handleCreateLink}
|
||||
handleClose={() => {
|
||||
setLinkModal(false);
|
||||
setSelectedLinkToUpdate(null);
|
||||
}}
|
||||
data={selectedLinkToUpdate}
|
||||
status={selectedLinkToUpdate ? true : false}
|
||||
createIssueLink={handleCreateLink}
|
||||
updateIssueLink={handleUpdateLink}
|
||||
/>
|
||||
<DeleteIssueModal
|
||||
handleClose={() => setDeleteIssueModal(false)}
|
||||
@ -396,7 +445,8 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
start_date: val,
|
||||
})
|
||||
}
|
||||
className="bg-custom-background-90 w-full"
|
||||
className="bg-custom-background-100"
|
||||
wrapperClassName="w-full"
|
||||
maxDate={maxDate ?? undefined}
|
||||
disabled={isNotAllowed || uneditable}
|
||||
/>
|
||||
@ -424,7 +474,8 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
target_date: val,
|
||||
})
|
||||
}
|
||||
className="bg-custom-background-90 w-full"
|
||||
className="bg-custom-background-100"
|
||||
wrapperClassName="w-full"
|
||||
minDate={minDate ?? undefined}
|
||||
disabled={isNotAllowed || uneditable}
|
||||
/>
|
||||
@ -488,6 +539,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
||||
<LinksList
|
||||
links={issueDetail.issue_link}
|
||||
handleDeleteLink={handleDeleteLink}
|
||||
handleEditLink={handleEditLink}
|
||||
userAuth={memberRole}
|
||||
/>
|
||||
) : null}
|
||||
|
@ -13,6 +13,8 @@ import useIssuesView from "hooks/use-issues-view";
|
||||
type Props = {
|
||||
issue: IIssue;
|
||||
partialUpdateIssue: (formData: Partial<IIssue>, issue: IIssue) => void;
|
||||
handleOnOpen?: () => void;
|
||||
handleOnClose?: () => void;
|
||||
tooltipPosition?: "top" | "bottom";
|
||||
noBorder?: boolean;
|
||||
user: ICurrentUserResponse | undefined;
|
||||
@ -22,6 +24,8 @@ type Props = {
|
||||
export const ViewDueDateSelect: React.FC<Props> = ({
|
||||
issue,
|
||||
partialUpdateIssue,
|
||||
handleOnOpen,
|
||||
handleOnClose,
|
||||
tooltipPosition = "top",
|
||||
noBorder = false,
|
||||
user,
|
||||
@ -80,6 +84,8 @@ export const ViewDueDateSelect: React.FC<Props> = ({
|
||||
}`}
|
||||
minDate={minDate ?? undefined}
|
||||
noBorder={noBorder}
|
||||
handleOnOpen={handleOnOpen}
|
||||
handleOnClose={handleOnClose}
|
||||
disabled={isNotAllowed}
|
||||
/>
|
||||
</div>
|
||||
|
@ -13,6 +13,8 @@ import useIssuesView from "hooks/use-issues-view";
|
||||
type Props = {
|
||||
issue: IIssue;
|
||||
partialUpdateIssue: (formData: Partial<IIssue>, issue: IIssue) => void;
|
||||
handleOnOpen?: () => void;
|
||||
handleOnClose?: () => void;
|
||||
tooltipPosition?: "top" | "bottom";
|
||||
noBorder?: boolean;
|
||||
user: ICurrentUserResponse | undefined;
|
||||
@ -22,6 +24,8 @@ type Props = {
|
||||
export const ViewStartDateSelect: React.FC<Props> = ({
|
||||
issue,
|
||||
partialUpdateIssue,
|
||||
handleOnOpen,
|
||||
handleOnClose,
|
||||
tooltipPosition = "top",
|
||||
noBorder = false,
|
||||
user,
|
||||
@ -72,6 +76,8 @@ export const ViewStartDateSelect: React.FC<Props> = ({
|
||||
}`}
|
||||
maxDate={maxDate ?? undefined}
|
||||
noBorder={noBorder}
|
||||
handleOnOpen={handleOnOpen}
|
||||
handleOnClose={handleOnClose}
|
||||
disabled={isNotAllowed}
|
||||
/>
|
||||
</div>
|
||||
|
@ -37,7 +37,7 @@ import { LinkIcon } from "@heroicons/react/20/solid";
|
||||
import { renderDateFormat, renderShortDateWithYearFormat } from "helpers/date-time.helper";
|
||||
import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper";
|
||||
// types
|
||||
import { ICurrentUserResponse, IIssue, IModule, ModuleLink } from "types";
|
||||
import { ICurrentUserResponse, IIssue, linkDetails, IModule, ModuleLink } from "types";
|
||||
// fetch-keys
|
||||
import { MODULE_DETAILS } from "constants/fetch-keys";
|
||||
// constant
|
||||
@ -61,6 +61,7 @@ type Props = {
|
||||
export const ModuleDetailsSidebar: React.FC<Props> = ({ module, isOpen, moduleIssues, user }) => {
|
||||
const [moduleDeleteModal, setModuleDeleteModal] = useState(false);
|
||||
const [moduleLinkModal, setModuleLinkModal] = useState(false);
|
||||
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<linkDetails | null>(null);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, moduleId } = router.query;
|
||||
@ -115,6 +116,37 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ module, isOpen, moduleIs
|
||||
});
|
||||
};
|
||||
|
||||
const handleUpdateLink = async (formData: ModuleLink, linkId: string) => {
|
||||
if (!workspaceSlug || !projectId || !module) return;
|
||||
|
||||
const payload = { metadata: {}, ...formData };
|
||||
|
||||
const updatedLinks = module.link_module.map((l) =>
|
||||
l.id === linkId
|
||||
? {
|
||||
...l,
|
||||
title: formData.title,
|
||||
url: formData.url,
|
||||
}
|
||||
: l
|
||||
);
|
||||
|
||||
mutate<IModule>(
|
||||
MODULE_DETAILS(module.id),
|
||||
(prevData) => ({ ...(prevData as IModule), link_module: updatedLinks }),
|
||||
false
|
||||
);
|
||||
|
||||
await modulesService
|
||||
.updateModuleLink(workspaceSlug as string, projectId as string, module.id, linkId, payload)
|
||||
.then((res) => {
|
||||
mutate(MODULE_DETAILS(module.id));
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
};
|
||||
|
||||
const handleDeleteLink = async (linkId: string) => {
|
||||
if (!workspaceSlug || !projectId || !module) return;
|
||||
|
||||
@ -170,12 +202,23 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ module, isOpen, moduleIs
|
||||
? Math.round((module.completed_issues / module.total_issues) * 100)
|
||||
: null;
|
||||
|
||||
const handleEditLink = (link: linkDetails) => {
|
||||
setSelectedLinkToUpdate(link);
|
||||
setModuleLinkModal(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<LinkModal
|
||||
isOpen={moduleLinkModal}
|
||||
handleClose={() => setModuleLinkModal(false)}
|
||||
onFormSubmit={handleCreateLink}
|
||||
handleClose={() => {
|
||||
setModuleLinkModal(false);
|
||||
setSelectedLinkToUpdate(null);
|
||||
}}
|
||||
data={selectedLinkToUpdate}
|
||||
status={selectedLinkToUpdate ? true : false}
|
||||
createIssueLink={handleCreateLink}
|
||||
updateIssueLink={handleUpdateLink}
|
||||
/>
|
||||
<DeleteModuleModal
|
||||
isOpen={moduleDeleteModal}
|
||||
@ -544,7 +587,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ module, isOpen, moduleIs
|
||||
</Disclosure>
|
||||
</div>
|
||||
|
||||
<div className="flex w-full flex-col border-t border-custom-border-200 px-6 py-6 text-xs">
|
||||
<div className="flex w-full flex-col border-t border-custom-border-200 px-6 pt-6 pb-10 text-xs">
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<h4 className="text-sm font-medium text-custom-text-200">Links</h4>
|
||||
<button
|
||||
@ -558,6 +601,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ module, isOpen, moduleIs
|
||||
{memberRole && module.link_module && module.link_module.length > 0 ? (
|
||||
<LinksList
|
||||
links={module.link_module}
|
||||
handleEditLink={handleEditLink}
|
||||
handleDeleteLink={handleDeleteLink}
|
||||
userAuth={memberRole}
|
||||
/>
|
||||
|
@ -80,7 +80,9 @@ export const NotificationCard: React.FC<NotificationCardProps> = (props) => {
|
||||
) : (
|
||||
<div className="w-12 h-12 bg-custom-background-80 rounded-full flex justify-center items-center">
|
||||
<span className="text-custom-text-100 font-medium text-lg">
|
||||
{notification.triggered_by_details.display_name?.[0] ? (
|
||||
{notification.triggered_by_details.is_bot ? (
|
||||
notification.triggered_by_details.first_name?.[0]?.toUpperCase()
|
||||
) : notification.triggered_by_details.display_name?.[0] ? (
|
||||
notification.triggered_by_details.display_name?.[0]?.toUpperCase()
|
||||
) : (
|
||||
<Icon iconName="person" className="h-6 w-6" />
|
||||
@ -91,7 +93,11 @@ export const NotificationCard: React.FC<NotificationCardProps> = (props) => {
|
||||
</div>
|
||||
<div className="space-y-2.5 w-full overflow-hidden">
|
||||
<div className="text-sm w-full break-words">
|
||||
<span className="font-semibold">{notification.triggered_by_details.display_name} </span>
|
||||
<span className="font-semibold">
|
||||
{notification.triggered_by_details.is_bot
|
||||
? notification.triggered_by_details.first_name
|
||||
: notification.triggered_by_details.display_name}{" "}
|
||||
</span>
|
||||
{notification.data.issue_activity.field !== "comment" &&
|
||||
notification.data.issue_activity.verb}{" "}
|
||||
{notification.data.issue_activity.field === "comment"
|
||||
|
@ -284,10 +284,7 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
|
||||
maxLength={255}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
id="tiptap-container"
|
||||
className="page-block-section relative -mt-2 text-custom-text-200"
|
||||
>
|
||||
<div className="page-block-section relative -mt-2 text-custom-text-200">
|
||||
<Controller
|
||||
name="description_html"
|
||||
control={control}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// ui
|
||||
import { BarGraph, ProfileEmptyState, Loader } from "components/ui";
|
||||
// image
|
||||
import priorityGraph from "public/empty-state/priority_graph.svg";
|
||||
import emptyBarGraph from "public/empty-state/empty_bar_graph.svg";
|
||||
// helpers
|
||||
import { capitalizeFirstLetter } from "helpers/string.helper";
|
||||
// types
|
||||
@ -67,7 +67,7 @@ export const ProfilePriorityDistribution: React.FC<Props> = ({ userProfile }) =>
|
||||
<ProfileEmptyState
|
||||
title="No Data yet"
|
||||
description="Create issues to view the them by priority in the graph for better analysis."
|
||||
image={priorityGraph}
|
||||
image={emptyBarGraph}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
@ -105,9 +105,11 @@ export const ProfileSidebar = () => {
|
||||
</div>
|
||||
<div className="px-5">
|
||||
<div className="mt-[38px]">
|
||||
<h4 className="text-lg font-semibold">{userProjectsData.user_data.display_name}</h4>
|
||||
<h4 className="text-lg font-semibold">
|
||||
{userProjectsData.user_data.first_name} {userProjectsData.user_data.last_name}
|
||||
</h4>
|
||||
<h6 className="text-custom-text-200 text-sm">
|
||||
{userProjectsData.user_data.display_name}
|
||||
({userProjectsData.user_data.display_name})
|
||||
</h6>
|
||||
</div>
|
||||
<div className="mt-6 space-y-5">
|
||||
|
@ -42,6 +42,7 @@ import { NETWORK_CHOICES } from "constants/project";
|
||||
type Props = {
|
||||
isOpen: boolean;
|
||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
setToFavorite?: boolean;
|
||||
user: ICurrentUserResponse | undefined;
|
||||
};
|
||||
|
||||
@ -74,7 +75,12 @@ const IsGuestCondition: React.FC<{
|
||||
return null;
|
||||
};
|
||||
|
||||
export const CreateProjectModal: React.FC<Props> = ({ isOpen, setIsOpen, user }) => {
|
||||
export const CreateProjectModal: React.FC<Props> = ({
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
setToFavorite = false,
|
||||
user,
|
||||
}) => {
|
||||
const [isChangeInIdentifierRequired, setIsChangeInIdentifierRequired] = useState(true);
|
||||
|
||||
const { setToastAlert } = useToast();
|
||||
@ -104,6 +110,29 @@ export const CreateProjectModal: React.FC<Props> = ({ isOpen, setIsOpen, user })
|
||||
reset(defaultValues);
|
||||
};
|
||||
|
||||
const handleAddToFavorites = (projectId: string) => {
|
||||
if (!workspaceSlug) return;
|
||||
|
||||
mutate<IProject[]>(
|
||||
PROJECTS_LIST(workspaceSlug as string, { is_favorite: "all" }),
|
||||
(prevData) =>
|
||||
(prevData ?? []).map((p) => (p.id === projectId ? { ...p, is_favorite: true } : p)),
|
||||
false
|
||||
);
|
||||
|
||||
projectServices
|
||||
.addProjectToFavorites(workspaceSlug as string, {
|
||||
project: projectId,
|
||||
})
|
||||
.catch(() =>
|
||||
setToastAlert({
|
||||
type: "error",
|
||||
title: "Error!",
|
||||
message: "Couldn't remove the project from favorites. Please try again.",
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const onSubmit = async (formData: IProject) => {
|
||||
if (!workspaceSlug) return;
|
||||
|
||||
@ -125,6 +154,9 @@ export const CreateProjectModal: React.FC<Props> = ({ isOpen, setIsOpen, user })
|
||||
title: "Success!",
|
||||
message: "Project created successfully.",
|
||||
});
|
||||
if (setToFavorite) {
|
||||
handleAddToFavorites(res.id);
|
||||
}
|
||||
handleClose();
|
||||
})
|
||||
.catch((err) => {
|
||||
|
@ -14,6 +14,9 @@ import { observer } from "mobx-react-lite";
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { RootStore } from "store/root";
|
||||
import { IProjectPublishSettingsViews } from "store/project-publish";
|
||||
// hooks
|
||||
import useToast from "hooks/use-toast";
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
|
||||
type Props = {
|
||||
// user: ICurrentUserResponse | undefined;
|
||||
@ -25,7 +28,7 @@ const defaultValues: Partial<any> = {
|
||||
reactions: false,
|
||||
votes: false,
|
||||
inbox: null,
|
||||
views: [],
|
||||
views: ["list", "kanban"],
|
||||
};
|
||||
|
||||
const viewOptions = [
|
||||
@ -40,6 +43,17 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
|
||||
const store: RootStore = useMobxStore();
|
||||
const { projectPublish } = store;
|
||||
|
||||
const { projectDetails, mutateProjectDetails } = useProjectDetails();
|
||||
|
||||
const { setToastAlert } = useToast();
|
||||
const handleToastAlert = (title: string, type: string, message: string) => {
|
||||
setToastAlert({
|
||||
title: title || "Title",
|
||||
type: "error" || "warning",
|
||||
message: message || "Message",
|
||||
});
|
||||
};
|
||||
|
||||
const { NEXT_PUBLIC_DEPLOY_URL } = process.env;
|
||||
const plane_deploy_url = NEXT_PUBLIC_DEPLOY_URL
|
||||
? NEXT_PUBLIC_DEPLOY_URL
|
||||
@ -111,32 +125,41 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
|
||||
}, [workspaceSlug, projectPublish, projectPublish.projectPublishModal]);
|
||||
|
||||
const onSettingsPublish = async (formData: any) => {
|
||||
const payload = {
|
||||
comments: formData.comments || false,
|
||||
reactions: formData.reactions || false,
|
||||
votes: formData.votes || false,
|
||||
inbox: formData.inbox || null,
|
||||
views: {
|
||||
list: formData.views.includes("list") || false,
|
||||
kanban: formData.views.includes("kanban") || false,
|
||||
calendar: formData.views.includes("calendar") || false,
|
||||
gantt: formData.views.includes("gantt") || false,
|
||||
spreadsheet: formData.views.includes("spreadsheet") || false,
|
||||
},
|
||||
};
|
||||
if (formData.views && formData.views.length > 0) {
|
||||
const payload = {
|
||||
comments: formData.comments || false,
|
||||
reactions: formData.reactions || false,
|
||||
votes: formData.votes || false,
|
||||
inbox: formData.inbox || null,
|
||||
views: {
|
||||
list: formData.views.includes("list") || false,
|
||||
kanban: formData.views.includes("kanban") || false,
|
||||
calendar: formData.views.includes("calendar") || false,
|
||||
gantt: formData.views.includes("gantt") || false,
|
||||
spreadsheet: formData.views.includes("spreadsheet") || false,
|
||||
},
|
||||
};
|
||||
|
||||
return projectPublish
|
||||
.createProjectSettingsAsync(
|
||||
workspaceSlug as string,
|
||||
projectPublish.project_id as string,
|
||||
payload,
|
||||
null
|
||||
)
|
||||
.then((response) => response)
|
||||
.catch((error) => {
|
||||
console.error("error", error);
|
||||
return error;
|
||||
});
|
||||
const _workspaceSlug = workspaceSlug;
|
||||
const _projectId = projectPublish.project_id;
|
||||
|
||||
return projectPublish
|
||||
.createProjectSettingsAsync(_workspaceSlug as string, _projectId as string, payload, null)
|
||||
.then((response) => {
|
||||
mutateProjectDetails();
|
||||
handleClose();
|
||||
console.log("_projectId", _projectId);
|
||||
if (_projectId)
|
||||
window.open(`${plane_deploy_url}/${_workspaceSlug}/${_projectId}`, "_blank");
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("error", error);
|
||||
return error;
|
||||
});
|
||||
} else {
|
||||
handleToastAlert("Missing fields", "warning", "Please select at least one view to publish");
|
||||
}
|
||||
};
|
||||
|
||||
const onSettingsUpdate = async (key: string, value: any) => {
|
||||
@ -171,7 +194,10 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
|
||||
payload,
|
||||
null
|
||||
)
|
||||
.then((response) => response)
|
||||
.then((response) => {
|
||||
mutateProjectDetails();
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("error", error);
|
||||
return error;
|
||||
@ -187,7 +213,9 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
|
||||
null
|
||||
)
|
||||
.then((response) => {
|
||||
mutateProjectDetails();
|
||||
reset({ ...defaultValues });
|
||||
handleClose();
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -13,7 +13,7 @@ import useTheme from "hooks/use-theme";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
import useProjects from "hooks/use-projects";
|
||||
// components
|
||||
import { DeleteProjectModal, SingleSidebarProject } from "components/project";
|
||||
import { CreateProjectModal, DeleteProjectModal, SingleSidebarProject } from "components/project";
|
||||
// services
|
||||
import projectService from "services/project.service";
|
||||
// icons
|
||||
@ -32,6 +32,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
||||
export const ProjectSidebarList: FC = () => {
|
||||
const store: any = useMobxStore();
|
||||
|
||||
const [isProjectModalOpen, setIsProjectModalOpen] = useState(false);
|
||||
const [deleteProjectModal, setDeleteProjectModal] = useState(false);
|
||||
const [projectToDelete, setProjectToDelete] = useState<IProject | null>(null);
|
||||
|
||||
@ -151,6 +152,12 @@ export const ProjectSidebarList: FC = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<CreateProjectModal
|
||||
isOpen={isProjectModalOpen}
|
||||
setIsOpen={setIsProjectModalOpen}
|
||||
setToFavorite
|
||||
user={user}
|
||||
/>
|
||||
<DeleteProjectModal
|
||||
isOpen={deleteProjectModal}
|
||||
onClose={() => setDeleteProjectModal(false)}
|
||||
@ -172,17 +179,25 @@ export const ProjectSidebarList: FC = () => {
|
||||
{({ open }) => (
|
||||
<>
|
||||
{!store?.theme?.sidebarCollapsed && (
|
||||
<Disclosure.Button
|
||||
as="button"
|
||||
type="button"
|
||||
className="group flex items-center gap-1 px-1.5 text-xs font-semibold text-custom-sidebar-text-400 text-left hover:bg-custom-sidebar-background-80 rounded w-full whitespace-nowrap"
|
||||
>
|
||||
Favorites
|
||||
<Icon
|
||||
iconName={open ? "arrow_drop_down" : "arrow_right"}
|
||||
className="group-hover:opacity-100 opacity-0 !text-lg"
|
||||
/>
|
||||
</Disclosure.Button>
|
||||
<div className="group flex justify-between items-center text-xs px-1.5 rounded text-custom-sidebar-text-400 hover:bg-custom-sidebar-background-80 w-full">
|
||||
<Disclosure.Button
|
||||
as="button"
|
||||
type="button"
|
||||
className="group flex items-center gap-1 px-1.5 text-xs font-semibold text-custom-sidebar-text-400 text-left hover:bg-custom-sidebar-background-80 rounded w-full whitespace-nowrap"
|
||||
>
|
||||
Favorites
|
||||
<Icon
|
||||
iconName={open ? "arrow_drop_down" : "arrow_right"}
|
||||
className="group-hover:opacity-100 opacity-0 !text-lg"
|
||||
/>
|
||||
</Disclosure.Button>
|
||||
<button
|
||||
className="group-hover:opacity-100 opacity-0"
|
||||
onClick={() => setIsProjectModalOpen(true)}
|
||||
>
|
||||
<Icon iconName="add" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<Disclosure.Panel as="div" className="space-y-2">
|
||||
{orderedFavProjects.map((project, index) => (
|
||||
@ -241,10 +256,7 @@ export const ProjectSidebarList: FC = () => {
|
||||
</Disclosure.Button>
|
||||
<button
|
||||
className="group-hover:opacity-100 opacity-0"
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", { key: "p" });
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
onClick={() => setIsProjectModalOpen(true)}
|
||||
>
|
||||
<Icon iconName="add" />
|
||||
</button>
|
||||
|
@ -97,10 +97,14 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
|
||||
{items.map((item, index) => (
|
||||
<button
|
||||
key={index}
|
||||
type="button"
|
||||
onClick={item.command}
|
||||
className={cn("p-2 text-custom-text-300 hover:bg-custom-primary-100/5 active:bg-custom-primary-100/5 transition-colors", {
|
||||
"text-custom-text-100 bg-custom-primary-100/5": item.isActive(),
|
||||
})}
|
||||
className={cn(
|
||||
"p-2 text-custom-text-300 hover:bg-custom-primary-100/5 active:bg-custom-primary-100/5 transition-colors",
|
||||
{
|
||||
"text-custom-text-100 bg-custom-primary-100/5": item.isActive(),
|
||||
}
|
||||
)}
|
||||
>
|
||||
<item.icon
|
||||
className={cn("h-4 w-4", {
|
||||
|
@ -19,7 +19,11 @@ export const LinkSelector: FC<LinkSelectorProps> = ({ editor, isOpen, setIsOpen
|
||||
return (
|
||||
<div className="relative">
|
||||
<button
|
||||
className={cn("flex h-full items-center space-x-2 px-3 py-1.5 text-sm font-medium text-custom-text-300 hover:bg-custom-background-100 active:bg-custom-background-100", { "bg-custom-background-100": isOpen })}
|
||||
type="button"
|
||||
className={cn(
|
||||
"flex h-full items-center space-x-2 px-3 py-1.5 text-sm font-medium text-custom-text-300 hover:bg-custom-background-100 active:bg-custom-background-100",
|
||||
{ "bg-custom-background-100": isOpen }
|
||||
)}
|
||||
onClick={() => {
|
||||
setIsOpen(!isOpen);
|
||||
}}
|
||||
@ -48,7 +52,7 @@ export const LinkSelector: FC<LinkSelectorProps> = ({ editor, isOpen, setIsOpen
|
||||
ref={inputRef}
|
||||
type="url"
|
||||
placeholder="Paste a link"
|
||||
className="flex-1 bg-custom-background-100 border border-custom-primary-300 p-1 text-sm outline-none placeholder:text-custom-text-400"
|
||||
className="flex-1 bg-custom-background-100 border-r border-custom-border-300 p-1 text-sm outline-none placeholder:text-custom-text-400"
|
||||
defaultValue={editor.getAttributes("link").href || ""}
|
||||
/>
|
||||
{editor.getAttributes("link").href ? (
|
||||
|
@ -91,8 +91,9 @@ export const NodeSelector: FC<NodeSelectorProps> = ({ editor, isOpen, setIsOpen
|
||||
return (
|
||||
<div className="relative h-full">
|
||||
<button
|
||||
className="flex h-full items-center gap-1 whitespace-nowrap p-2 text-sm font-medium text-custom-text-300 hover:bg-custom-primary-100/5 active:bg-custom-primary-100/5"
|
||||
type="button"
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className="flex h-full items-center gap-1 whitespace-nowrap p-2 text-sm font-medium text-custom-text-300 hover:bg-custom-primary-100/5 active:bg-custom-primary-100/5"
|
||||
>
|
||||
<span>{activeItem?.name}</span>
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
@ -103,11 +104,15 @@ export const NodeSelector: FC<NodeSelectorProps> = ({ editor, isOpen, setIsOpen
|
||||
{items.map((item, index) => (
|
||||
<button
|
||||
key={index}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
item.command();
|
||||
setIsOpen(false);
|
||||
}}
|
||||
className={cn("flex items-center justify-between rounded-sm px-2 py-1 text-sm text-custom-text-200 hover:bg-custom-primary-100/5 hover:text-custom-text-100", { "bg-custom-primary-100/5 text-custom-text-100": activeItem.name === item.name })}
|
||||
className={cn(
|
||||
"flex items-center justify-between rounded-sm px-2 py-1 text-sm text-custom-text-200 hover:bg-custom-primary-100/5 hover:text-custom-text-100",
|
||||
{ "bg-custom-primary-100/5 text-custom-text-100": activeItem.name === item.name }
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="rounded-sm border border-custom-border-300 p-1">
|
||||
|
@ -112,20 +112,21 @@ const Tiptap = (props: ITiptapRichTextEditor) => {
|
||||
}, 500);
|
||||
}, 1000);
|
||||
|
||||
const editorClassNames = `relative w-full max-w-screen-lg sm:rounded-lg sm:shadow-lg mt-2 p-3 relative focus:outline-none rounded-md
|
||||
${noBorder ? '' : 'border border-custom-border-200'
|
||||
} ${borderOnFocus ? 'focus:border border-custom-border-300' : 'focus:border-0'
|
||||
} ${customClassName}`;
|
||||
const editorClassNames = `relative w-full max-w-screen-lg mt-2 p-3 relative focus:outline-none rounded-lg
|
||||
${noBorder ? "" : "border border-custom-border-200"} ${
|
||||
borderOnFocus ? "focus:border border-custom-border-300" : "focus:border-0"
|
||||
} ${customClassName}`;
|
||||
|
||||
if (!editor) return null;
|
||||
editorRef.current = editor;
|
||||
|
||||
return (
|
||||
<div
|
||||
id="tiptap-container"
|
||||
onClick={() => {
|
||||
editor?.chain().focus().run();
|
||||
}}
|
||||
className={`tiptap-editor-container ${editorClassNames}`}
|
||||
className={`tiptap-editor-container cursor-text ${editorClassNames}`}
|
||||
>
|
||||
{editor && <EditorBubbleMenu editor={editor} />}
|
||||
<div className={`${editorContentCustomClassNames}`}>
|
||||
|
@ -264,7 +264,10 @@ const CommandList = ({
|
||||
>
|
||||
{items.map((item: CommandItemProps, index: number) => (
|
||||
<button
|
||||
className={cn(`flex w-full items-center space-x-2 rounded-md px-2 py-1 text-left text-sm text-custom-text-200 hover:bg-custom-primary-100/5 hover:text-custom-text-100`, { "bg-custom-primary-100/5 text-custom-text-100": index === selectedIndex })}
|
||||
className={cn(
|
||||
`flex w-full items-center space-x-2 rounded-md px-2 py-1 text-left text-sm text-custom-text-200 hover:bg-custom-primary-100/5 hover:text-custom-text-100`,
|
||||
{ "bg-custom-primary-100/5 text-custom-text-100": index === selectedIndex }
|
||||
)}
|
||||
key={index}
|
||||
onClick={() => selectItem(index)}
|
||||
>
|
||||
@ -282,8 +285,6 @@ const renderItems = () => {
|
||||
let component: ReactRenderer | null = null;
|
||||
let popup: any | null = null;
|
||||
|
||||
const container = document.querySelector("#tiptap-container") as HTMLElement;
|
||||
|
||||
return {
|
||||
onStart: (props: { editor: Editor; clientRect: DOMRect }) => {
|
||||
component = new ReactRenderer(CommandList, {
|
||||
@ -294,7 +295,7 @@ const renderItems = () => {
|
||||
// @ts-ignore
|
||||
popup = tippy("body", {
|
||||
getReferenceClientRect: props.clientRect,
|
||||
appendTo: () => container,
|
||||
appendTo: () => document.querySelector("#tiptap-container"),
|
||||
content: component.element,
|
||||
showOnCreate: true,
|
||||
interactive: true,
|
||||
|
@ -106,7 +106,7 @@ export const AssigneesList: React.FC<AsigneesListProps> = ({
|
||||
))}
|
||||
{users.length > length ? (
|
||||
<div className="-ml-3.5 relative h-6 w-6 rounded">
|
||||
<div className="grid place-items-center rounded bg-custom-background-80 text-xs capitalize h-6 w-6 text-custom-text-200 border-[0.5px] border-custom-border-300">
|
||||
<div className="flex items-center rounded bg-custom-background-80 text-xs capitalize h-6 w-6 text-custom-text-200 border-[0.5px] border-custom-border-300">
|
||||
<Icon iconName="add" className="text-xs !leading-3 -mr-0.5" />
|
||||
{users.length - length}
|
||||
</div>
|
||||
|
@ -8,10 +8,13 @@ type Props = {
|
||||
renderAs?: "input" | "button";
|
||||
value: Date | string | null | undefined;
|
||||
onChange: (val: string | null) => void;
|
||||
handleOnOpen?: () => void;
|
||||
handleOnClose?: () => void;
|
||||
placeholder?: string;
|
||||
displayShortForm?: boolean;
|
||||
error?: boolean;
|
||||
noBorder?: boolean;
|
||||
wrapperClassName?: string;
|
||||
className?: string;
|
||||
isClearable?: boolean;
|
||||
disabled?: boolean;
|
||||
@ -23,10 +26,13 @@ export const CustomDatePicker: React.FC<Props> = ({
|
||||
renderAs = "button",
|
||||
value,
|
||||
onChange,
|
||||
handleOnOpen,
|
||||
handleOnClose,
|
||||
placeholder = "Select date",
|
||||
displayShortForm = false,
|
||||
error = false,
|
||||
noBorder = false,
|
||||
wrapperClassName = "",
|
||||
className = "",
|
||||
isClearable = true,
|
||||
disabled = false,
|
||||
@ -40,6 +46,9 @@ export const CustomDatePicker: React.FC<Props> = ({
|
||||
if (!val) onChange(null);
|
||||
else onChange(renderDateFormat(val));
|
||||
}}
|
||||
onCalendarOpen={handleOnOpen}
|
||||
onCalendarClose={handleOnClose}
|
||||
wrapperClassName={wrapperClassName}
|
||||
className={`${
|
||||
renderAs === "input"
|
||||
? "block px-2 py-2 text-sm focus:outline-none"
|
||||
|
@ -1,7 +1,11 @@
|
||||
import React from "react";
|
||||
// ui
|
||||
import { Tooltip } from "components/ui";
|
||||
// types
|
||||
import { IIssueLabels } from "types";
|
||||
|
||||
type IssueLabelsListProps = {
|
||||
labels?: (string | undefined)[];
|
||||
labels?: (IIssueLabels | undefined)[];
|
||||
length?: number;
|
||||
showLength?: boolean;
|
||||
};
|
||||
@ -14,18 +18,16 @@ export const IssueLabelsList: React.FC<IssueLabelsListProps> = ({
|
||||
<>
|
||||
{labels && (
|
||||
<>
|
||||
{labels.slice(0, length).map((color, index) => (
|
||||
<div className={`flex h-4 w-4 rounded-full ${index ? "-ml-3.5" : ""}`}>
|
||||
<span
|
||||
className={`h-4 w-4 flex-shrink-0 rounded-full border border-custom-border-200
|
||||
`}
|
||||
style={{
|
||||
backgroundColor: color && color !== "" ? color : "#000000",
|
||||
}}
|
||||
/>
|
||||
<Tooltip
|
||||
position="top"
|
||||
tooltipHeading="Labels"
|
||||
tooltipContent={labels.map((l) => l?.name).join(", ")}
|
||||
>
|
||||
<div className="flex items-center gap-1.5 px-2 py-1 text-custom-text-200 rounded shadow-sm border border-custom-border-300">
|
||||
<span className="h-2 w-2 flex-shrink-0 rounded-full bg-custom-primary" />
|
||||
{`${labels.length} Labels`}
|
||||
</div>
|
||||
))}
|
||||
{labels.length > length ? <span>+{labels.length - length}</span> : null}
|
||||
</Tooltip>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
@ -11,8 +11,8 @@ type Props = {
|
||||
export const ProfileEmptyState: React.FC<Props> = ({ title, description, image }) => (
|
||||
<div className={`h-full w-full mx-auto grid place-items-center p-8 `}>
|
||||
<div className="text-center flex flex-col items-center w-full">
|
||||
<div className="flex items-center justify-center h-14 w-14 rounded-full bg-custom-primary-10">
|
||||
<Image src={image} className="w-8" alt={title} />
|
||||
<div className="flex items-center justify-center h-14 w-14 rounded-full bg-custom-background-90">
|
||||
<Image src={image} width={32} alt={title} />
|
||||
</div>
|
||||
<h6 className="text-base font-semibold mt-3.5 mb-3">{title}</h6>
|
||||
{description && <p className="text-sm text-custom-text-300">{description}</p>}
|
||||
|
@ -45,12 +45,14 @@ export const IssuesList: React.FC<Props> = ({ issues, type }) => {
|
||||
>
|
||||
<h4 className="capitalize">{type}</h4>
|
||||
<h4 className="col-span-2">Issue</h4>
|
||||
<h4>Due Date</h4>
|
||||
<h4>{type === "overdue" ? "Due" : "Start"} Date</h4>
|
||||
</div>
|
||||
<div className="max-h-72 overflow-y-scroll">
|
||||
{issues.length > 0 ? (
|
||||
issues.map((issue) => {
|
||||
const dateDifference = getDateDifference(new Date(issue.target_date as string));
|
||||
const date = type === "overdue" ? issue.target_date : issue.start_date;
|
||||
|
||||
const dateDifference = getDateDifference(new Date(date as string));
|
||||
|
||||
return (
|
||||
<Link
|
||||
@ -75,7 +77,7 @@ export const IssuesList: React.FC<Props> = ({ issues, type }) => {
|
||||
</h5>
|
||||
<h5 className="col-span-2">{truncateText(issue.name, 30)}</h5>
|
||||
<h5 className="cursor-default">
|
||||
{renderShortDateWithYearFormat(new Date(issue.target_date as string))}
|
||||
{renderShortDateWithYearFormat(new Date(date?.toString() ?? ""))}
|
||||
</h5>
|
||||
</div>
|
||||
</a>
|
||||
|
@ -42,10 +42,10 @@ export const ANALYTICS_X_AXIS_VALUES: { value: TXAxisValues; label: string }[] =
|
||||
value: "target_date",
|
||||
label: "Due date",
|
||||
},
|
||||
// {
|
||||
// value: "start_date",
|
||||
// label: "Start date",
|
||||
// },
|
||||
{
|
||||
value: "start_date",
|
||||
label: "Start date",
|
||||
},
|
||||
{
|
||||
value: "created_at",
|
||||
label: "Created date",
|
||||
|
@ -362,7 +362,13 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
|
||||
},
|
||||
});
|
||||
|
||||
if (property === "kanban") {
|
||||
const additionalProperties = {
|
||||
groupByProperty: state.groupByProperty,
|
||||
orderBy: state.orderBy,
|
||||
};
|
||||
|
||||
if (property === "kanban" && state.groupByProperty === null) {
|
||||
additionalProperties.groupByProperty = "state";
|
||||
dispatch({
|
||||
type: "SET_GROUP_BY_PROPERTY",
|
||||
payload: {
|
||||
@ -371,6 +377,7 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
|
||||
});
|
||||
}
|
||||
if (property === "calendar") {
|
||||
additionalProperties.groupByProperty = null;
|
||||
dispatch({
|
||||
type: "SET_GROUP_BY_PROPERTY",
|
||||
payload: {
|
||||
@ -378,13 +385,22 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
|
||||
},
|
||||
});
|
||||
}
|
||||
if (property === "gantt_chart") {
|
||||
additionalProperties.orderBy = "sort_order";
|
||||
dispatch({
|
||||
type: "SET_ORDER_BY_PROPERTY",
|
||||
payload: {
|
||||
orderBy: "sort_order",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
|
||||
saveDataToServer(workspaceSlug as string, projectId as string, {
|
||||
...state,
|
||||
issueView: property,
|
||||
groupByProperty: "state",
|
||||
...additionalProperties,
|
||||
});
|
||||
},
|
||||
[workspaceSlug, projectId, state]
|
||||
|
@ -1,5 +1,12 @@
|
||||
// next imports
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
// icons
|
||||
import { Bars3Icon } from "@heroicons/react/24/outline";
|
||||
// ui components
|
||||
import { Tooltip } from "components/ui";
|
||||
// hooks
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
|
||||
type Props = {
|
||||
breadcrumbs?: JSX.Element;
|
||||
@ -9,27 +16,61 @@ type Props = {
|
||||
noHeader: boolean;
|
||||
};
|
||||
|
||||
const Header: React.FC<Props> = ({ breadcrumbs, left, right, setToggleSidebar, noHeader }) => (
|
||||
<div
|
||||
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 px-5 py-4 ${
|
||||
noHeader ? "md:hidden" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
|
||||
<div className="block md:hidden">
|
||||
<button
|
||||
type="button"
|
||||
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
|
||||
onClick={() => setToggleSidebar((prevData) => !prevData)}
|
||||
>
|
||||
<Bars3Icon className="h-5 w-5" />
|
||||
</button>
|
||||
const { NEXT_PUBLIC_DEPLOY_URL } = process.env;
|
||||
const plane_deploy_url = NEXT_PUBLIC_DEPLOY_URL ? NEXT_PUBLIC_DEPLOY_URL : "http://localhost:3001";
|
||||
|
||||
const Header: React.FC<Props> = ({ breadcrumbs, left, right, setToggleSidebar, noHeader }) => {
|
||||
const { projectDetails } = useProjectDetails();
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 px-5 py-4 ${
|
||||
noHeader ? "md:hidden" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
|
||||
<div className="block md:hidden">
|
||||
<button
|
||||
type="button"
|
||||
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
|
||||
onClick={() => setToggleSidebar((prevData) => !prevData)}
|
||||
>
|
||||
<Bars3Icon className="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
<div>{breadcrumbs}</div>
|
||||
|
||||
{projectDetails && projectDetails?.is_deployed && (
|
||||
<Link href={`${plane_deploy_url}/${workspaceSlug}/${projectId}`}>
|
||||
<a target="_blank" rel="noreferrer">
|
||||
<Tooltip
|
||||
tooltipContent="This project is public, and live on web."
|
||||
position="bottom-left"
|
||||
>
|
||||
<div className="transition-all flex-shrink-0 bg-custom-primary-100/20 text-custom-primary-100 p-1 rounded overflow-hidden relative flex items-center gap-1 cursor-pointer group">
|
||||
<div className="w-[14px] h-[14px] flex justify-center items-center">
|
||||
<span className="material-symbols-rounded text-[14px]">
|
||||
radio_button_checked
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-xs font-medium">Public</div>
|
||||
<div className="w-[14px] h-[14px] hidden group-hover:flex justify-center items-center">
|
||||
<span className="material-symbols-rounded text-[14px]">open_in_new</span>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</a>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
<div className="flex-shrink-0">{left}</div>
|
||||
</div>
|
||||
{breadcrumbs}
|
||||
<div className="flex-shrink-0">{left}</div>
|
||||
<div className="flex-shrink-0">{right}</div>
|
||||
</div>
|
||||
<div className="flex-shrink-0">{right}</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
|
@ -1,5 +1,5 @@
|
||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.718262 14.3359C0.718262 13.2314 1.61369 12.3359 2.71826 12.3359H4.91545C6.02002 12.3359 6.91544 13.2314 6.91544 14.3359V27.0542H0.718262V14.3359Z" fill="#C5D6FF"/>
|
||||
<path d="M10.7886 2.71875C10.7886 1.61418 11.684 0.71875 12.7886 0.71875H14.9858C16.0903 0.71875 16.9858 1.61418 16.9858 2.71875V27.0568H10.7886V2.71875Z" fill="#9FBBFF"/>
|
||||
<path d="M20.8589 9.6875C20.8589 8.58293 21.7543 7.6875 22.8589 7.6875H25.0561C26.1606 7.6875 27.0561 8.58293 27.0561 9.6875V27.0537H20.8589V9.6875Z" fill="#C5D6FF"/>
|
||||
<path d="M0.718262 14.3359C0.718262 13.2314 1.61369 12.3359 2.71826 12.3359H4.91545C6.02002 12.3359 6.91544 13.2314 6.91544 14.3359V27.0542H0.718262V14.3359Z" fill="#DEE2E6"/>
|
||||
<path d="M10.7886 2.71875C10.7886 1.61418 11.684 0.71875 12.7886 0.71875H14.9858C16.0903 0.71875 16.9858 1.61418 16.9858 2.71875V27.0568H10.7886V2.71875Z" fill="#CED4DA"/>
|
||||
<path d="M20.8591 9.6875C20.8591 8.58293 21.7546 7.6875 22.8591 7.6875H25.0563C26.1609 7.6875 27.0563 8.58293 27.0563 9.6875V27.0537H20.8591V9.6875Z" fill="#DEE2E6"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 618 B After Width: | Height: | Size: 618 B |
10
apps/app/public/empty-state/empty_graph.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg width="37" height="26" viewBox="0 0 37 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 23.4992C1 23.4992 1.4588 24.9268 4.50198 25.0001H5C11.2284 24.8579 11 17.9987 11.5 13.9989C12 9.99916 11.8458 0.903962 17 1.00077C21.2817 1.08118 23.8932 13.213 28 11.9989C29.9905 11.4105 33.5 5.00007 33.5 5.00007V25.0001H5C4.82675 25.004 4.66084 25.0039 4.50198 25.0001H1V23.4992Z" fill="url(#paint0_linear_6920_91013)"/>
|
||||
<path d="M1.47602 23.3462C1.39154 23.0833 1.10992 22.9387 0.847024 23.0231C0.584123 23.1076 0.43949 23.3892 0.523977 23.6521L1.47602 23.3462ZM5 25.0001L5.01141 25.4999L5 25.0001ZM17 1.00077L17.0094 0.500855L17 1.00077ZM28 11.9989L28.1417 12.4784L28 11.9989ZM30.8333 5.00007C30.8333 6.47282 32.0272 7.66673 33.5 7.66673C34.9728 7.66673 36.1667 6.47282 36.1667 5.00007C36.1667 3.52731 34.9728 2.3334 33.5 2.3334C32.0272 2.3334 30.8333 3.52731 30.8333 5.00007ZM1 23.4992C0.523977 23.6521 0.52413 23.6526 0.524285 23.6531C0.52434 23.6533 0.524498 23.6538 0.524608 23.6541C0.524828 23.6548 0.525058 23.6555 0.525298 23.6562C0.525777 23.6576 0.526296 23.6592 0.526856 23.6608C0.527975 23.6641 0.529258 23.6678 0.530714 23.6719C0.533627 23.6801 0.537237 23.6898 0.541628 23.7009C0.550409 23.723 0.562322 23.7509 0.578044 23.7836C0.6095 23.849 0.656181 23.9336 0.723434 24.0304C0.85859 24.2247 1.07399 24.4637 1.40832 24.6923C2.07953 25.1511 3.1901 25.5415 5.01141 25.4999L4.98859 24.5002C3.31786 24.5383 2.42842 24.1783 1.97265 23.8667C1.74348 23.7101 1.61364 23.5589 1.54443 23.4594C1.5095 23.4092 1.48921 23.3709 1.47925 23.3502C1.47426 23.3399 1.47185 23.3339 1.47149 23.3329C1.4713 23.3325 1.47164 23.3333 1.47241 23.3355C1.4728 23.3366 1.4733 23.338 1.47391 23.3398C1.47421 23.3407 1.47454 23.3416 1.47489 23.3427C1.47507 23.3432 1.47525 23.3438 1.47544 23.3444C1.47553 23.3447 1.47568 23.3451 1.47573 23.3453C1.47587 23.3457 1.47602 23.3462 1 23.4992ZM5.01141 25.4999C6.66694 25.4621 7.93434 24.9744 8.89485 24.1662C9.84776 23.3644 10.4597 22.2801 10.8699 21.1118C11.2798 19.9446 11.4979 18.6657 11.6457 17.4454C11.7197 16.8339 11.7767 16.2309 11.8304 15.6611C11.8844 15.0885 11.9348 14.5519 11.9961 14.061L11.0039 13.9369C10.9402 14.4459 10.8884 14.9987 10.8348 15.5673C10.781 16.1387 10.7251 16.7289 10.6529 17.3252C10.5082 18.5203 10.3005 19.7151 9.9264 20.7804C9.5527 21.8447 9.02264 22.7518 8.25102 23.401C7.48698 24.0439 6.44728 24.4669 4.98859 24.5002L5.01141 25.4999ZM11.9961 14.061C12.1219 13.0547 12.2094 11.7012 12.3432 10.315C12.479 8.90792 12.665 7.42713 12.9907 6.08122C13.318 4.72822 13.776 3.55792 14.4276 2.73995C15.062 1.94357 15.8775 1.47977 16.9906 1.50068L17.0094 0.500855C15.5454 0.473358 14.4474 1.11016 13.6454 2.11689C12.8607 3.10204 12.3596 4.43737 12.0187 5.84604C11.6761 7.26181 11.4848 8.79873 11.3478 10.2189C11.2088 11.66 11.1281 12.9433 11.0039 13.9369L11.9961 14.061ZM16.9906 1.50068C17.822 1.51629 18.6613 2.12546 19.5584 3.23777C20.4409 4.33201 21.276 5.77974 22.1347 7.23885C22.979 8.67358 23.8508 10.128 24.7826 11.1422C25.7068 12.1481 26.8286 12.8666 28.1417 12.4784L27.8583 11.5194C27.118 11.7383 26.3733 11.3955 25.519 10.4657C24.6724 9.54415 23.8537 8.1882 22.9965 6.73168C22.1537 5.29954 21.2765 3.77513 20.3368 2.60999C19.4116 1.46291 18.3189 0.525449 17.0094 0.500855L16.9906 1.50068ZM28.1417 12.4784C28.4806 12.3783 28.8126 12.1684 29.1222 11.9181C29.4369 11.6636 29.7572 11.3437 30.0725 10.9897C30.7031 10.2817 31.3428 9.40414 31.9115 8.55769C32.4817 7.70903 32.9879 6.88053 33.3511 6.26503C33.5329 5.95699 33.6793 5.70163 33.7805 5.52293C33.831 5.43356 33.8703 5.36332 33.8971 5.31521C33.9105 5.29115 33.9207 5.27262 33.9277 5.25999C33.9312 5.25367 33.9338 5.24883 33.9356 5.24551C33.9366 5.24385 33.9373 5.24258 33.9377 5.24168C33.938 5.24124 33.9382 5.24089 33.9383 5.24063C33.9384 5.24051 33.9385 5.24039 33.9385 5.24033C33.9385 5.24024 33.9386 5.24017 33.5 5.00007C33.0614 4.75996 33.0614 4.75994 33.0614 4.75995C33.0614 4.75998 33.0614 4.76001 33.0614 4.76008C33.0613 4.76022 33.0612 4.76045 33.061 4.76078C33.0606 4.76144 33.06 4.76249 33.0593 4.76391C33.0577 4.76676 33.0553 4.77113 33.0521 4.77696C33.0456 4.78862 33.0359 4.80616 33.0231 4.82919C32.9975 4.87527 32.9594 4.94333 32.9102 5.0304C32.8116 5.20456 32.6683 5.45462 32.4899 5.75676C32.133 6.3616 31.6374 7.17248 31.0814 7.99999C30.5239 8.82971 29.913 9.66513 29.3257 10.3246C29.0321 10.6543 28.7517 10.9317 28.4935 11.1404C28.2302 11.3533 28.0171 11.4725 27.8583 11.5194L28.1417 12.4784Z" fill="#ACB5BD"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_6920_91013" x1="17" y1="0.5" x2="17.25" y2="25.003" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.253958" stop-color="#C6CED6" stop-opacity="0.7"/>
|
||||
<stop offset="1" stop-color="#858E96" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 4.6 KiB |
3
apps/app/public/empty-state/empty_users.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="43" height="42" viewBox="0 0 43 42" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21.5 21.375C27.1977 21.375 31.8125 16.7602 31.8125 11.0625C31.8125 5.36484 27.1977 0.75 21.5 0.75C15.8023 0.75 11.1875 5.36484 11.1875 11.0625C11.1875 16.7602 15.8023 21.375 21.5 21.375ZM21.5 26.5312C14.6164 26.5312 0.875 29.9859 0.875 36.8438V42H42.125V36.8438C42.125 29.9859 28.3836 26.5312 21.5 26.5312Z" fill="#CED4DA"/>
|
||||
</svg>
|
After Width: | Height: | Size: 438 B |
@ -1,3 +1,3 @@
|
||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.3704 21.7617C11.349 21.5892 9.64994 20.7655 8.27325 19.2907C6.89653 17.816 6.20817 16.0515 6.20817 13.9974C6.20817 11.8239 6.96342 9.98197 8.47392 8.47148C9.98441 6.96098 11.8264 6.20573 13.9998 6.20573C16.0539 6.20573 17.8184 6.89181 19.2932 8.26397C20.768 9.63613 21.5916 11.3402 21.7642 13.3762L20.0506 12.8449C19.7825 11.3974 19.0895 10.1969 17.9714 9.24335C16.8532 8.28984 15.5294 7.81308 13.9998 7.81308C12.2835 7.81308 10.8237 8.4147 9.62039 9.61795C8.41714 10.8212 7.81552 12.281 7.81552 13.9974C7.81552 15.5157 8.29456 16.8389 9.25262 17.9668C10.2107 19.0946 11.4089 19.793 12.8474 20.0618L13.3704 21.7617ZM13.9998 27.4557C12.1381 27.4557 10.3885 27.1024 8.75109 26.396C7.11366 25.6896 5.68932 24.7308 4.47807 23.5198C3.26682 22.3088 2.30791 20.8847 1.60135 19.2475C0.894785 17.6104 0.541504 15.8611 0.541504 13.9997C0.541504 12.1383 0.894726 10.3887 1.60117 8.75084C2.30762 7.11296 3.26634 5.68825 4.47736 4.47669C5.6884 3.26511 7.11249 2.30594 8.74964 1.59919C10.3868 0.89244 12.136 0.539062 13.9974 0.539062C15.8588 0.539062 17.6085 0.892345 19.2463 1.59891C20.8842 2.30547 22.3089 3.26438 23.5205 4.47563C24.7321 5.68688 25.6912 7.11122 26.398 8.74865C27.1047 10.3861 27.4581 12.1356 27.4581 13.9974C27.4581 14.1735 27.4545 14.3497 27.4472 14.5259C27.4399 14.702 27.4245 14.8782 27.4009 15.0544L25.8508 14.5804V13.9974C25.8508 10.6991 24.7002 7.89934 22.399 5.59816C20.0978 3.297 17.2981 2.14641 13.9998 2.14641C10.7015 2.14641 7.90178 3.297 5.6006 5.59816C3.29944 7.89934 2.14885 10.6991 2.14885 13.9974C2.14885 17.2956 3.29944 20.0954 5.6006 22.3966C7.90178 24.6977 10.7015 25.8483 13.9998 25.8483H14.5828L15.0704 27.3984C14.892 27.422 14.7136 27.4375 14.5351 27.4448C14.3567 27.452 14.1783 27.4557 13.9998 27.4557ZM25.156 27.284L19.1079 21.2223L18.0999 24.2953C18.0033 24.555 17.8256 24.679 17.567 24.6672C17.3084 24.6554 17.1437 24.5196 17.0728 24.2599L14.2831 14.94C14.2214 14.7366 14.265 14.5604 14.4139 14.4115C14.5628 14.2625 14.739 14.219 14.9424 14.2807L24.2759 17.0704C24.5266 17.1412 24.6578 17.306 24.6696 17.5646C24.6814 17.8232 24.562 17.9963 24.3113 18.0838L21.2247 19.1055L27.2864 25.1536C27.3954 25.2592 27.4499 25.3837 27.4499 25.527C27.4499 25.6704 27.3954 25.7965 27.2864 25.9055L25.9079 27.284C25.8023 27.393 25.6778 27.4474 25.5344 27.4474C25.3911 27.4474 25.265 27.393 25.156 27.284Z" fill="#9FBBFF"/>
|
||||
<path d="M13.3707 21.7617C11.3493 21.5892 9.65018 20.7655 8.27349 19.2907C6.89677 17.816 6.20842 16.0515 6.20842 13.9974C6.20842 11.8239 6.96366 9.98197 8.47416 8.47148C9.98466 6.96098 11.8266 6.20573 14 6.20573C16.0542 6.20573 17.8187 6.89181 19.2934 8.26397C20.7682 9.63613 21.5919 11.3402 21.7644 13.3762L20.0508 12.8449C19.7828 11.3974 19.0897 10.1969 17.9716 9.24335C16.8535 8.28984 15.5296 7.81308 14 7.81308C12.2837 7.81308 10.8239 8.4147 9.62063 9.61795C8.41739 10.8212 7.81577 12.281 7.81577 13.9974C7.81577 15.5157 8.2948 16.8389 9.25287 17.9668C10.2109 19.0946 11.4092 19.793 12.8476 20.0618L13.3707 21.7617ZM14 27.4557C12.1383 27.4557 10.3887 27.1024 8.75133 26.396C7.1139 25.6896 5.68956 24.7308 4.47831 23.5198C3.26706 22.3088 2.30815 20.8847 1.60159 19.2475C0.895029 17.6104 0.541748 15.8611 0.541748 13.9997C0.541748 12.1383 0.894971 10.3887 1.60142 8.75084C2.30786 7.11296 3.26659 5.68825 4.4776 4.47669C5.68864 3.26511 7.11273 2.30594 8.74988 1.59919C10.387 0.89244 12.1363 0.539062 13.9977 0.539062C15.8591 0.539062 17.6087 0.892345 19.2466 1.59891C20.8844 2.30547 22.3092 3.26438 23.5207 4.47563C24.7323 5.68688 25.6915 7.11122 26.3982 8.74865C27.105 10.3861 27.4583 12.1356 27.4583 13.9974C27.4583 14.1735 27.4547 14.3497 27.4474 14.5259C27.4402 14.702 27.4247 14.8782 27.4011 15.0544L25.851 14.5804V13.9974C25.851 10.6991 24.7004 7.89934 22.3993 5.59816C20.0981 3.297 17.2983 2.14641 14 2.14641C10.7018 2.14641 7.90203 3.297 5.60084 5.59816C3.29968 7.89934 2.1491 10.6991 2.1491 13.9974C2.1491 17.2956 3.29968 20.0954 5.60084 22.3966C7.90203 24.6977 10.7018 25.8483 14 25.8483H14.583L15.0707 27.3984C14.8923 27.422 14.7138 27.4375 14.5354 27.4448C14.3569 27.452 14.1785 27.4557 14 27.4557ZM25.1563 27.284L19.1082 21.2223L18.1002 24.2953C18.0035 24.555 17.8259 24.679 17.5672 24.6672C17.3086 24.6554 17.1439 24.5196 17.0731 24.2599L14.2834 14.94C14.2216 14.7366 14.2652 14.5604 14.4141 14.4115C14.5631 14.2625 14.7393 14.219 14.9427 14.2807L24.2762 17.0704C24.5268 17.1412 24.658 17.306 24.6699 17.5646C24.6817 17.8232 24.5622 17.9963 24.3116 18.0838L21.2249 19.1055L27.2866 25.1536C27.3956 25.2592 27.4501 25.3837 27.4501 25.527C27.4501 25.6704 27.3956 25.7965 27.2866 25.9055L25.9082 27.284C25.8025 27.393 25.678 27.4474 25.5347 27.4474C25.3914 27.4474 25.2652 27.393 25.1563 27.284Z" fill="#CED4DA"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
@ -1,26 +1,26 @@
|
||||
<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="path-1-inside-1_6456_90931" fill="white">
|
||||
<mask id="path-1-inside-1_6456_90192" fill="white">
|
||||
<path d="M34 17C34 26.3888 26.3888 34 17 34C7.61116 34 0 26.3888 0 17C0 7.61116 7.61116 0 17 0C26.3888 0 34 7.61116 34 17ZM5.09529 17C5.09529 23.5748 10.4252 28.9047 17 28.9047C23.5748 28.9047 28.9047 23.5748 28.9047 17C28.9047 10.4252 23.5748 5.09529 17 5.09529C10.4252 5.09529 5.09529 10.4252 5.09529 17Z"/>
|
||||
</mask>
|
||||
<path d="M34 17C34 26.3888 26.3888 34 17 34C7.61116 34 0 26.3888 0 17C0 7.61116 7.61116 0 17 0C26.3888 0 34 7.61116 34 17ZM5.09529 17C5.09529 23.5748 10.4252 28.9047 17 28.9047C23.5748 28.9047 28.9047 23.5748 28.9047 17C28.9047 10.4252 23.5748 5.09529 17 5.09529C10.4252 5.09529 5.09529 10.4252 5.09529 17Z" fill="#C5D6FF" stroke="#ECF1FF" stroke-width="0.482269" mask="url(#path-1-inside-1_6456_90931)"/>
|
||||
<mask id="path-2-inside-2_6456_90931" fill="white">
|
||||
<path d="M34 17C34 26.3888 26.3888 34 17 34C7.61116 34 0 26.3888 0 17C0 7.61116 7.61116 0 17 0C26.3888 0 34 7.61116 34 17ZM5.09529 17C5.09529 23.5748 10.4252 28.9047 17 28.9047C23.5748 28.9047 28.9047 23.5748 28.9047 17C28.9047 10.4252 23.5748 5.09529 17 5.09529C10.4252 5.09529 5.09529 10.4252 5.09529 17Z" fill="#DEE2E6" stroke="#F8F9FA" stroke-width="0.482269" mask="url(#path-1-inside-1_6456_90192)"/>
|
||||
<mask id="path-2-inside-2_6456_90192" fill="white">
|
||||
<path d="M17 0C19.8546 3.40409e-08 22.6633 0.718838 25.1669 2.09021C27.6705 3.46158 29.7885 5.44133 31.3255 7.84684C32.8625 10.2524 33.769 13.0062 33.9613 15.8543C34.1537 18.7024 33.6258 21.5531 32.4263 24.1435C31.2268 26.7339 29.3943 28.9804 27.0978 30.6761C24.8013 32.3717 22.1149 33.4617 19.2862 33.8456C16.4575 34.2295 13.5777 33.8949 10.9124 32.8727C8.24708 31.8504 5.8821 30.1735 4.03558 27.9965L7.92131 24.7006C9.21439 26.2251 10.8705 27.3994 12.737 28.1153C14.6034 28.8311 16.6201 29.0654 18.601 28.7966C20.5818 28.5277 22.4631 27.7644 24.0713 26.577C25.6794 25.3896 26.9627 23.8164 27.8027 22.0024C28.6427 20.1885 29.0124 18.1922 28.8776 16.1977C28.7429 14.2032 28.1081 12.2748 27.0318 10.5903C25.9555 8.90572 24.4723 7.51935 22.7191 6.55901C20.9659 5.59867 18.999 5.09529 17 5.09529V0Z"/>
|
||||
</mask>
|
||||
<path d="M17 0C19.8546 3.40409e-08 22.6633 0.718838 25.1669 2.09021C27.6705 3.46158 29.7885 5.44133 31.3255 7.84684C32.8625 10.2524 33.769 13.0062 33.9613 15.8543C34.1537 18.7024 33.6258 21.5531 32.4263 24.1435C31.2268 26.7339 29.3943 28.9804 27.0978 30.6761C24.8013 32.3717 22.1149 33.4617 19.2862 33.8456C16.4575 34.2295 13.5777 33.8949 10.9124 32.8727C8.24708 31.8504 5.8821 30.1735 4.03558 27.9965L7.92131 24.7006C9.21439 26.2251 10.8705 27.3994 12.737 28.1153C14.6034 28.8311 16.6201 29.0654 18.601 28.7966C20.5818 28.5277 22.4631 27.7644 24.0713 26.577C25.6794 25.3896 26.9627 23.8164 27.8027 22.0024C28.6427 20.1885 29.0124 18.1922 28.8776 16.1977C28.7429 14.2032 28.1081 12.2748 27.0318 10.5903C25.9555 8.90572 24.4723 7.51935 22.7191 6.55901C20.9659 5.59867 18.999 5.09529 17 5.09529V0Z" fill="#9FBBFF" stroke="#ECF1FF" stroke-width="0.482269" mask="url(#path-2-inside-2_6456_90931)"/>
|
||||
<mask id="path-3-inside-3_6456_90931" fill="white">
|
||||
<path d="M17 0C19.8546 3.40409e-08 22.6633 0.718838 25.1669 2.09021C27.6705 3.46158 29.7885 5.44133 31.3255 7.84684C32.8625 10.2524 33.769 13.0062 33.9613 15.8543C34.1537 18.7024 33.6258 21.5531 32.4263 24.1435C31.2268 26.7339 29.3943 28.9804 27.0978 30.6761C24.8013 32.3717 22.1149 33.4617 19.2862 33.8456C16.4575 34.2295 13.5777 33.8949 10.9124 32.8727C8.24708 31.8504 5.8821 30.1735 4.03558 27.9965L7.92131 24.7006C9.21439 26.2251 10.8705 27.3994 12.737 28.1153C14.6034 28.8311 16.6201 29.0654 18.601 28.7966C20.5818 28.5277 22.4631 27.7644 24.0713 26.577C25.6794 25.3896 26.9627 23.8164 27.8027 22.0024C28.6427 20.1885 29.0124 18.1922 28.8776 16.1977C28.7429 14.2032 28.1081 12.2748 27.0318 10.5903C25.9555 8.90572 24.4723 7.51935 22.7191 6.55901C20.9659 5.59867 18.999 5.09529 17 5.09529V0Z" fill="#ACB5BD" stroke="#F8F9FA" stroke-width="0.482269" mask="url(#path-2-inside-2_6456_90192)"/>
|
||||
<mask id="path-3-inside-3_6456_90192" fill="white">
|
||||
<path d="M17 0C21.3598 5.19899e-08 25.5529 1.67502 28.7128 4.67885C31.8726 7.68269 33.7577 11.7857 33.9782 16.1399C34.1988 20.4941 32.7381 24.7666 29.898 28.0744C27.0578 31.3822 23.0554 33.4724 18.718 33.913C14.3805 34.3536 10.0395 33.1109 6.5923 30.4417C3.14507 27.7726 0.855066 23.881 0.195603 19.5714C-0.46386 15.2618 0.557627 10.8635 3.04894 7.28569C5.54025 3.70783 9.31095 1.22387 13.5817 0.347219L14.6062 5.33844C11.6155 5.95234 8.975 7.69179 7.23039 10.1973C5.48578 12.7028 4.77045 15.7828 5.23226 18.8007C5.69407 21.8186 7.2977 24.5438 9.71173 26.4129C12.1257 28.2821 15.1656 29.1523 18.203 28.8438C21.2405 28.5352 24.0433 27.0715 26.0321 24.7552C28.021 22.4388 29.0439 19.4469 28.8895 16.3977C28.735 13.3486 27.415 10.4753 25.2022 8.37178C22.9894 6.26826 20.0531 5.09529 17 5.09529V0Z"/>
|
||||
</mask>
|
||||
<path d="M17 0C21.3598 5.19899e-08 25.5529 1.67502 28.7128 4.67885C31.8726 7.68269 33.7577 11.7857 33.9782 16.1399C34.1988 20.4941 32.7381 24.7666 29.898 28.0744C27.0578 31.3822 23.0554 33.4724 18.718 33.913C14.3805 34.3536 10.0395 33.1109 6.5923 30.4417C3.14507 27.7726 0.855066 23.881 0.195603 19.5714C-0.46386 15.2618 0.557627 10.8635 3.04894 7.28569C5.54025 3.70783 9.31095 1.22387 13.5817 0.347219L14.6062 5.33844C11.6155 5.95234 8.975 7.69179 7.23039 10.1973C5.48578 12.7028 4.77045 15.7828 5.23226 18.8007C5.69407 21.8186 7.2977 24.5438 9.71173 26.4129C12.1257 28.2821 15.1656 29.1523 18.203 28.8438C21.2405 28.5352 24.0433 27.0715 26.0321 24.7552C28.021 22.4388 29.0439 19.4469 28.8895 16.3977C28.735 13.3486 27.415 10.4753 25.2022 8.37178C22.9894 6.26826 20.0531 5.09529 17 5.09529V0Z" fill="#C5D6FF" stroke="#ECF1FF" stroke-width="0.482269" mask="url(#path-3-inside-3_6456_90931)"/>
|
||||
<mask id="path-4-inside-4_6456_90931" fill="white">
|
||||
<path d="M17 0C21.3598 5.19899e-08 25.5529 1.67502 28.7128 4.67885C31.8726 7.68269 33.7577 11.7857 33.9782 16.1399C34.1988 20.4941 32.7381 24.7666 29.898 28.0744C27.0578 31.3822 23.0554 33.4724 18.718 33.913C14.3805 34.3536 10.0395 33.1109 6.5923 30.4417C3.14507 27.7726 0.855066 23.881 0.195603 19.5714C-0.46386 15.2618 0.557627 10.8635 3.04894 7.28569C5.54025 3.70783 9.31095 1.22387 13.5817 0.347219L14.6062 5.33844C11.6155 5.95234 8.975 7.69179 7.23039 10.1973C5.48578 12.7028 4.77045 15.7828 5.23226 18.8007C5.69407 21.8186 7.2977 24.5438 9.71173 26.4129C12.1257 28.2821 15.1656 29.1523 18.203 28.8438C21.2405 28.5352 24.0433 27.0715 26.0321 24.7552C28.021 22.4388 29.0439 19.4469 28.8895 16.3977C28.735 13.3486 27.415 10.4753 25.2022 8.37178C22.9894 6.26826 20.0531 5.09529 17 5.09529V0Z" fill="#CED4DA" stroke="#F8F9FA" stroke-width="0.482269" mask="url(#path-3-inside-3_6456_90192)"/>
|
||||
<mask id="path-4-inside-4_6456_90192" fill="white">
|
||||
<path d="M17 0C21.5087 5.37655e-08 25.8327 1.79107 29.0208 4.97918C32.2089 8.1673 34 12.4913 34 17C34 21.5087 32.2089 25.8327 29.0208 29.0208C25.8327 32.2089 21.5087 34 17 34V28.9047C20.1573 28.9047 23.1853 27.6505 25.4179 25.4179C27.6505 23.1853 28.9047 20.1573 28.9047 17C28.9047 13.8427 27.6505 10.8147 25.4179 8.5821C23.1853 6.34953 20.1573 5.09529 17 5.09529V0Z"/>
|
||||
</mask>
|
||||
<path d="M17 0C21.5087 5.37655e-08 25.8327 1.79107 29.0208 4.97918C32.2089 8.1673 34 12.4913 34 17C34 21.5087 32.2089 25.8327 29.0208 29.0208C25.8327 32.2089 21.5087 34 17 34V28.9047C20.1573 28.9047 23.1853 27.6505 25.4179 25.4179C27.6505 23.1853 28.9047 20.1573 28.9047 17C28.9047 13.8427 27.6505 10.8147 25.4179 8.5821C23.1853 6.34953 20.1573 5.09529 17 5.09529V0Z" fill="#9FBBFF" stroke="#ECF1FF" stroke-width="0.482269" mask="url(#path-4-inside-4_6456_90931)"/>
|
||||
<mask id="path-5-inside-5_6456_90931" fill="white">
|
||||
<path d="M17 0C21.5087 5.37655e-08 25.8327 1.79107 29.0208 4.97918C32.2089 8.1673 34 12.4913 34 17C34 21.5087 32.2089 25.8327 29.0208 29.0208C25.8327 32.2089 21.5087 34 17 34V28.9047C20.1573 28.9047 23.1853 27.6505 25.4179 25.4179C27.6505 23.1853 28.9047 20.1573 28.9047 17C28.9047 13.8427 27.6505 10.8147 25.4179 8.5821C23.1853 6.34953 20.1573 5.09529 17 5.09529V0Z" fill="#E9ECEF" stroke="#F8F9FA" stroke-width="0.482269" mask="url(#path-4-inside-4_6456_90192)"/>
|
||||
<mask id="path-5-inside-5_6456_90192" fill="white">
|
||||
<path d="M17 0C19.9437 3.51029e-08 22.8369 0.764364 25.3965 2.21827C27.956 3.67217 30.0942 5.76578 31.6017 8.29416C33.1091 10.8225 33.9342 13.699 33.9962 16.642C34.0582 19.5851 33.3549 22.4937 31.9553 25.0833L27.4728 22.6606C28.453 20.8471 28.9455 18.8103 28.9021 16.7493C28.8587 14.6884 28.2809 12.6741 27.2252 10.9035C26.1696 9.13293 24.6722 7.66682 22.8798 6.64869C21.0874 5.63055 19.0614 5.09529 17 5.09529V0Z"/>
|
||||
</mask>
|
||||
<path d="M17 0C19.9437 3.51029e-08 22.8369 0.764364 25.3965 2.21827C27.956 3.67217 30.0942 5.76578 31.6017 8.29416C33.1091 10.8225 33.9342 13.699 33.9962 16.642C34.0582 19.5851 33.3549 22.4937 31.9553 25.0833L27.4728 22.6606C28.453 20.8471 28.9455 18.8103 28.9021 16.7493C28.8587 14.6884 28.2809 12.6741 27.2252 10.9035C26.1696 9.13293 24.6722 7.66682 22.8798 6.64869C21.0874 5.63055 19.0614 5.09529 17 5.09529V0Z" fill="#C5D6FF" stroke="#ECF1FF" stroke-width="0.482269" mask="url(#path-5-inside-5_6456_90931)"/>
|
||||
<mask id="path-6-inside-6_6456_90931" fill="white">
|
||||
<path d="M17 0C19.9437 3.51029e-08 22.8369 0.764364 25.3965 2.21827C27.956 3.67217 30.0942 5.76578 31.6017 8.29416C33.1091 10.8225 33.9342 13.699 33.9962 16.642C34.0582 19.5851 33.3549 22.4937 31.9553 25.0833L27.4728 22.6606C28.453 20.8471 28.9455 18.8103 28.9021 16.7493C28.8587 14.6884 28.2809 12.6741 27.2252 10.9035C26.1696 9.13293 24.6722 7.66682 22.8798 6.64869C21.0874 5.63055 19.0614 5.09529 17 5.09529V0Z" fill="#DEE2E6" stroke="#F8F9FA" stroke-width="0.482269" mask="url(#path-5-inside-5_6456_90192)"/>
|
||||
<mask id="path-6-inside-6_6456_90192" fill="white">
|
||||
<path d="M17 0C20.6461 4.34798e-08 24.1957 1.17228 27.1246 3.34381C30.0536 5.51533 32.2068 8.57102 33.2664 12.0598L28.391 13.5405C27.649 11.0974 26.1411 8.95755 24.0901 7.43688C22.039 5.91621 19.5533 5.09529 17 5.09529V0Z"/>
|
||||
</mask>
|
||||
<path d="M17 0C20.6461 4.34798e-08 24.1957 1.17228 27.1246 3.34381C30.0536 5.51533 32.2068 8.57102 33.2664 12.0598L28.391 13.5405C27.649 11.0974 26.1411 8.95755 24.0901 7.43688C22.039 5.91621 19.5533 5.09529 17 5.09529V0Z" fill="#9FBBFF" stroke="#ECF1FF" stroke-width="0.482269" mask="url(#path-6-inside-6_6456_90931)"/>
|
||||
<path d="M17 0C20.6461 4.34798e-08 24.1957 1.17228 27.1246 3.34381C30.0536 5.51533 32.2068 8.57102 33.2664 12.0598L28.391 13.5405C27.649 11.0974 26.1411 8.95755 24.0901 7.43688C22.039 5.91621 19.5533 5.09529 17 5.09529V0Z" fill="#E9ECEF" stroke="#F8F9FA" stroke-width="0.482269" mask="url(#path-6-inside-6_6456_90192)"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
@ -459,6 +459,29 @@ class ProjectIssuesServices extends APIService {
|
||||
});
|
||||
}
|
||||
|
||||
async updateIssueLink(
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
issueId: string,
|
||||
linkId: string,
|
||||
data: {
|
||||
metadata: any;
|
||||
title: string;
|
||||
url: string;
|
||||
},
|
||||
|
||||
): Promise<any> {
|
||||
return this.patch(
|
||||
`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/${linkId}/`,
|
||||
data
|
||||
)
|
||||
.then((response) => response?.data)
|
||||
.catch((error) => {
|
||||
throw error?.response;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async deleteIssueLink(
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
|
@ -212,6 +212,28 @@ class ProjectIssuesServices extends APIService {
|
||||
});
|
||||
}
|
||||
|
||||
async updateModuleLink(
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
moduleId: string,
|
||||
linkId: string,
|
||||
data: {
|
||||
metadata: any;
|
||||
title: string;
|
||||
url: string;
|
||||
},
|
||||
|
||||
): Promise<any> {
|
||||
return this.patch(
|
||||
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/`,
|
||||
data
|
||||
)
|
||||
.then((response) => response?.data)
|
||||
.catch((error) => {
|
||||
throw error?.response;
|
||||
});
|
||||
}
|
||||
|
||||
async deleteModuleLink(
|
||||
workspaceSlug: string,
|
||||
projectId: string,
|
||||
|
@ -259,15 +259,13 @@ class ProjectPublishStore implements IProjectPublishStore {
|
||||
user
|
||||
);
|
||||
|
||||
if (response) {
|
||||
runInAction(() => {
|
||||
this.projectPublishSettings = "not-initialized";
|
||||
this.loader = false;
|
||||
this.error = null;
|
||||
});
|
||||
runInAction(() => {
|
||||
this.projectPublishSettings = "not-initialized";
|
||||
this.loader = false;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.loader = false;
|
||||
this.error = error;
|
||||
|
23
apps/app/types/issues.d.ts
vendored
@ -56,6 +56,16 @@ export interface IIssueLink {
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface linkDetails {
|
||||
created_at: Date;
|
||||
created_by: string;
|
||||
created_by_detail: IUserLite;
|
||||
id: string;
|
||||
metadata: any;
|
||||
title: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface IIssue {
|
||||
archived_at: string;
|
||||
assignees: string[];
|
||||
@ -80,15 +90,7 @@ export interface IIssue {
|
||||
estimate_point: number | null;
|
||||
id: string;
|
||||
issue_cycle: IIssueCycle | null;
|
||||
issue_link: {
|
||||
created_at: Date;
|
||||
created_by: string;
|
||||
created_by_detail: IUserLite;
|
||||
id: string;
|
||||
metadata: any;
|
||||
title: string;
|
||||
url: string;
|
||||
}[];
|
||||
issue_link: linkDetails[];
|
||||
issue_module: IIssueModule | null;
|
||||
labels: string[];
|
||||
label_details: any[];
|
||||
@ -205,7 +207,8 @@ export interface IIssueLite {
|
||||
id: string;
|
||||
name: string;
|
||||
project_id: string;
|
||||
target_date: string;
|
||||
start_date?: string | null;
|
||||
target_date?: string | null;
|
||||
workspace__slug: string;
|
||||
}
|
||||
|
||||
|
11
apps/app/types/modules.d.ts
vendored
@ -7,6 +7,7 @@ import type {
|
||||
IWorkspaceLite,
|
||||
IProjectLite,
|
||||
IIssueFilterOptions,
|
||||
linkDetails,
|
||||
} from "types";
|
||||
|
||||
export interface IModule {
|
||||
@ -26,15 +27,7 @@ export interface IModule {
|
||||
id: string;
|
||||
lead: string | null;
|
||||
lead_detail: IUserLite | null;
|
||||
link_module: {
|
||||
created_at: Date;
|
||||
created_by: string;
|
||||
created_by_detail: IUserLite;
|
||||
id: string;
|
||||
metadata: any;
|
||||
title: string;
|
||||
url: string;
|
||||
}[];
|
||||
link_module: linkDetails[];
|
||||
links_list: ModuleLink[];
|
||||
members: string[];
|
||||
members_list: string[];
|
||||
|
1
apps/app/types/projects.d.ts
vendored
@ -57,6 +57,7 @@ export interface IProject {
|
||||
updated_by: string;
|
||||
workspace: IWorkspace | string;
|
||||
workspace_detail: IWorkspaceLite;
|
||||
is_deployed: boolean;
|
||||
}
|
||||
|
||||
export interface IProjectLite {
|
||||
|
30
apps/space/app/404/page.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
// next imports
|
||||
import Image from "next/image";
|
||||
|
||||
const Custom404Error = () => (
|
||||
<div className="relative w-screen min-h-screen h-full flex justify-center items-center py-5">
|
||||
<div className="max-w-[700px] space-y-5">
|
||||
<div className="flex items-center flex-col gap-3 text-center">
|
||||
<div className="relative w-[240px] h-[240px]">
|
||||
<Image src={`/404.svg`} layout="fill" alt="404- Page not found" />
|
||||
</div>
|
||||
<div className="text-xl font-medium">Oops! Something went wrong.</div>
|
||||
<div className="text-sm text-custom-text-200">
|
||||
Sorry, the page you are looking for cannot be found. It may have been removed, had its name changed, or is
|
||||
temporarily unavailable.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-center flex justify-center items-center">
|
||||
<a
|
||||
href={`https://app.plane.so/`}
|
||||
className="transition-all border border-gray-200 bg-gray-50 hover:bg-gray-100 text-gray-700 hover:text-gray-800 cursor-pointer p-1.5 px-2.5 rounded-sm text-sm font-medium hover:scale-105 select-none"
|
||||
>
|
||||
Go to your Workspace
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Custom404Error;
|
@ -7,6 +7,7 @@ import IssueNavbar from "components/issues/navbar";
|
||||
import IssueFilter from "components/issues/filters-render";
|
||||
// service
|
||||
import ProjectService from "services/project.service";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
type LayoutProps = {
|
||||
params: { workspace_slug: string; project_slug: string };
|
||||
@ -17,17 +18,26 @@ export async function generateMetadata({ params }: LayoutProps): Promise<Metadat
|
||||
const { workspace_slug, project_slug } = params;
|
||||
const projectServiceInstance = new ProjectService();
|
||||
|
||||
const project = await projectServiceInstance?.getProjectSettingsAsync(workspace_slug, project_slug);
|
||||
try {
|
||||
const project = await projectServiceInstance?.getProjectSettingsAsync(workspace_slug, project_slug);
|
||||
|
||||
return {
|
||||
title: `${project?.project_details?.name} | ${workspace_slug}`,
|
||||
description: `${project?.project_details?.description || `${project?.project_details?.name} | ${workspace_slug}`}`,
|
||||
icons: `data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>${
|
||||
typeof project?.project_details?.emoji != "object"
|
||||
? String.fromCodePoint(parseInt(project?.project_details?.emoji))
|
||||
: "✈️"
|
||||
}</text></svg>`,
|
||||
};
|
||||
return {
|
||||
title: `${project?.project_details?.name} | ${workspace_slug}`,
|
||||
description: `${
|
||||
project?.project_details?.description || `${project?.project_details?.name} | ${workspace_slug}`
|
||||
}`,
|
||||
icons: `data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>${
|
||||
typeof project?.project_details?.emoji != "object"
|
||||
? String.fromCodePoint(parseInt(project?.project_details?.emoji))
|
||||
: "✈️"
|
||||
}</text></svg>`,
|
||||
};
|
||||
} catch (error: any) {
|
||||
if (error?.data?.error) {
|
||||
redirect(`/project-not-published`);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const RootLayout = ({ children }: { children: React.ReactNode }) => (
|
||||
|
@ -29,15 +29,41 @@ const WorkspaceProjectPage = observer(() => {
|
||||
|
||||
// updating default board view when we are in the issues page
|
||||
useEffect(() => {
|
||||
if (workspace_slug && project_slug) {
|
||||
if (!board) {
|
||||
store.issue.setCurrentIssueBoardView("list");
|
||||
router.replace(`/${workspace_slug}/${project_slug}?board=${store?.issue?.currentIssueBoardView}`);
|
||||
} else {
|
||||
if (board != store?.issue?.currentIssueBoardView) store.issue.setCurrentIssueBoardView(board);
|
||||
if (workspace_slug && project_slug && store?.project?.workspaceProjectSettings) {
|
||||
const workspacePRojectSettingViews = store?.project?.workspaceProjectSettings?.views;
|
||||
const userAccessViews: TIssueBoardKeys[] = [];
|
||||
|
||||
Object.keys(workspacePRojectSettingViews).filter((_key) => {
|
||||
if (_key === "list" && workspacePRojectSettingViews.list === true) userAccessViews.push(_key);
|
||||
if (_key === "kanban" && workspacePRojectSettingViews.kanban === true) userAccessViews.push(_key);
|
||||
if (_key === "calendar" && workspacePRojectSettingViews.calendar === true) userAccessViews.push(_key);
|
||||
if (_key === "spreadsheet" && workspacePRojectSettingViews.spreadsheet === true) userAccessViews.push(_key);
|
||||
if (_key === "gantt" && workspacePRojectSettingViews.gantt === true) userAccessViews.push(_key);
|
||||
});
|
||||
|
||||
if (userAccessViews && userAccessViews.length > 0) {
|
||||
if (!board) {
|
||||
store.issue.setCurrentIssueBoardView(userAccessViews[0]);
|
||||
router.replace(`/${workspace_slug}/${project_slug}?board=${userAccessViews[0]}`);
|
||||
} else {
|
||||
if (userAccessViews.includes(board)) {
|
||||
if (store.issue.currentIssueBoardView === null) store.issue.setCurrentIssueBoardView(board);
|
||||
else {
|
||||
if (board === store.issue.currentIssueBoardView)
|
||||
router.replace(`/${workspace_slug}/${project_slug}?board=${board}`);
|
||||
else {
|
||||
store.issue.setCurrentIssueBoardView(board);
|
||||
router.replace(`/${workspace_slug}/${project_slug}?board=${board}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
store.issue.setCurrentIssueBoardView(userAccessViews[0]);
|
||||
router.replace(`/${workspace_slug}/${project_slug}?board=${userAccessViews[0]}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [workspace_slug, project_slug, board, router, store?.issue]);
|
||||
}, [workspace_slug, project_slug, board, router, store?.issue, store?.project?.workspaceProjectSettings]);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace_slug && project_slug) {
|
||||
|
31
apps/space/app/project-not-published/page.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
// next imports
|
||||
import Image from "next/image";
|
||||
|
||||
const CustomProjectNotPublishedError = () => (
|
||||
<div className="relative w-screen min-h-screen h-full flex justify-center items-center py-5">
|
||||
<div className="max-w-[700px] space-y-5">
|
||||
<div className="flex items-center flex-col gap-3 text-center">
|
||||
<div className="relative w-[240px] h-[240px]">
|
||||
<Image src={`/project-not-published.svg`} layout="fill" alt="404- Page not found" />
|
||||
</div>
|
||||
<div className="text-xl font-medium">
|
||||
Oops! The page you{`'`}re looking for isn{`'`}t live at the moment.
|
||||
</div>
|
||||
<div className="text-sm text-custom-text-200">
|
||||
If this is your project, login to your workspace to adjust its visibility settings and make it public.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-center flex justify-center items-center">
|
||||
<a
|
||||
href={`https://app.plane.so/`}
|
||||
className="transition-all border border-gray-200 bg-gray-50 hover:bg-gray-100 text-gray-700 hover:text-gray-800 cursor-pointer p-1.5 px-2.5 rounded-sm text-sm font-medium hover:scale-105 select-none"
|
||||
>
|
||||
Go to your Workspace
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default CustomProjectNotPublishedError;
|
@ -27,7 +27,7 @@ export const IssueListBlock = ({ issue }: { issue: IIssue }) => {
|
||||
<div className="font-medium text-gray-800 h-full line-clamp-2">{issue.name}</div>
|
||||
|
||||
{/* priority */}
|
||||
<div className="relative flex items-center gap-3 w-full">
|
||||
<div className="relative flex flex-wrap items-center gap-2 w-full">
|
||||
{issue?.priority && (
|
||||
<div className="flex-shrink-0">
|
||||
<IssueBlockPriority priority={issue?.priority} />
|
||||
|
@ -24,11 +24,6 @@ const MobxStoreInit = () => {
|
||||
else localStorage.setItem("app_theme", _theme && _theme != "light" ? "dark" : "light");
|
||||
}, [store?.theme]);
|
||||
|
||||
// updating default board view when we are in the issues page
|
||||
useEffect(() => {
|
||||
if (board && board != store?.issue?.currentIssueBoardView) store.issue.setCurrentIssueBoardView(board);
|
||||
}, [board, store?.issue]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
"js-cookie": "^3.0.1",
|
||||
"mobx": "^6.10.0",
|
||||
"mobx-react-lite": "^4.0.3",
|
||||
"next": "^13.4.13",
|
||||
"next": "^13.4.16",
|
||||
"nprogress": "^0.2.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
17
apps/space/public/404.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<svg width="596" height="568" viewBox="0 0 596 568" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="293" cy="284" r="284" fill="#F1F3F5"/>
|
||||
<path d="M191.016 181.117H178.242V174.008H190.293V169.477H178.242V162.68H191.016V157.816H172.344V186H191.016V181.117ZM230.172 162.426H235.191C238.121 162.426 239.957 164.184 239.957 166.918C239.957 169.711 238.219 171.41 235.25 171.41H230.172V162.426ZM230.172 175.688H234.898L240.152 186H246.832L240.895 174.809C244.137 173.539 246.012 170.414 246.012 166.801C246.012 161.234 242.301 157.816 235.816 157.816H224.273V186H230.172V175.688ZM284.797 162.426H289.816C292.746 162.426 294.582 164.184 294.582 166.918C294.582 169.711 292.844 171.41 289.875 171.41H284.797V162.426ZM284.797 175.688H289.523L294.777 186H301.457L295.52 174.809C298.762 173.539 300.637 170.414 300.637 166.801C300.637 161.234 296.926 157.816 290.441 157.816H278.898V186H284.797V175.688ZM346.238 157.328C337.879 157.328 332.645 162.934 332.645 171.918C332.645 180.883 337.879 186.488 346.238 186.488C354.578 186.488 359.832 180.883 359.832 171.918C359.832 162.934 354.578 157.328 346.238 157.328ZM346.238 162.25C350.848 162.25 353.797 166 353.797 171.918C353.797 177.816 350.848 181.547 346.238 181.547C341.609 181.547 338.66 177.816 338.66 171.918C338.66 166 341.629 162.25 346.238 162.25ZM398.539 162.426H403.559C406.488 162.426 408.324 164.184 408.324 166.918C408.324 169.711 406.586 171.41 403.617 171.41H398.539V162.426ZM398.539 175.688H403.266L408.52 186H415.199L409.262 174.809C412.504 173.539 414.379 170.414 414.379 166.801C414.379 161.234 410.668 157.816 404.184 157.816H392.641V186H398.539V175.688Z" fill="black"/>
|
||||
<path d="M191.016 181.117H178.242V174.008H190.293V169.477H178.242V162.68H191.016V157.816H172.344V186H191.016V181.117ZM230.172 162.426H235.191C238.121 162.426 239.957 164.184 239.957 166.918C239.957 169.711 238.219 171.41 235.25 171.41H230.172V162.426ZM230.172 175.688H234.898L240.152 186H246.832L240.895 174.809C244.137 173.539 246.012 170.414 246.012 166.801C246.012 161.234 242.301 157.816 235.816 157.816H224.273V186H230.172V175.688ZM284.797 162.426H289.816C292.746 162.426 294.582 164.184 294.582 166.918C294.582 169.711 292.844 171.41 289.875 171.41H284.797V162.426ZM284.797 175.688H289.523L294.777 186H301.457L295.52 174.809C298.762 173.539 300.637 170.414 300.637 166.801C300.637 161.234 296.926 157.816 290.441 157.816H278.898V186H284.797V175.688ZM346.238 157.328C337.879 157.328 332.645 162.934 332.645 171.918C332.645 180.883 337.879 186.488 346.238 186.488C354.578 186.488 359.832 180.883 359.832 171.918C359.832 162.934 354.578 157.328 346.238 157.328ZM346.238 162.25C350.848 162.25 353.797 166 353.797 171.918C353.797 177.816 350.848 181.547 346.238 181.547C341.609 181.547 338.66 177.816 338.66 171.918C338.66 166 341.629 162.25 346.238 162.25ZM398.539 162.426H403.559C406.488 162.426 408.324 164.184 408.324 166.918C408.324 169.711 406.586 171.41 403.617 171.41H398.539V162.426ZM398.539 175.688H403.266L408.52 186H415.199L409.262 174.809C412.504 173.539 414.379 170.414 414.379 166.801C414.379 161.234 410.668 157.816 404.184 157.816H392.641V186H398.539V175.688Z" fill="black"/>
|
||||
<mask id="mask0_468_2978" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="10" y="258" width="568" height="222">
|
||||
<path d="M115.723 475H157.764V437.354H185.303V401.904H157.764V263.623H95.3613C52.002 327.49 29.0039 364.551 10.5469 399.707V437.354H115.723V475ZM49.3652 402.051C66.5039 368.945 84.9609 340.088 115.723 294.971H116.602V403.223H49.3652V402.051ZM292.857 479.688C346.031 479.688 378.258 437.061 378.258 368.799C378.258 300.537 345.738 258.789 292.857 258.789C239.977 258.789 207.311 300.684 207.311 368.945C207.311 437.354 239.684 479.688 292.857 479.688ZM292.857 444.238C267.662 444.238 252.281 416.992 252.281 368.945C252.281 321.338 267.955 294.238 292.857 294.238C317.906 294.238 333.287 321.191 333.287 368.945C333.287 417.139 318.053 444.238 292.857 444.238ZM507.785 475H549.826V437.354H577.365V401.904H549.826V263.623H487.424C444.064 327.49 421.066 364.551 402.609 399.707V437.354H507.785V475ZM441.428 402.051C458.566 368.945 477.023 340.088 507.785 294.971H508.664V403.223H441.428V402.051Z" fill="#858E96"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_468_2978)">
|
||||
<path d="M369.5 527L243 223.5H-27.5V527H369.5Z" fill="#858E96"/>
|
||||
</g>
|
||||
<mask id="mask1_468_2978" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="19" y="277" width="568" height="222">
|
||||
<path d="M124.723 494H166.764V456.354H194.303V420.904H166.764V282.623H104.361C61.002 346.49 38.0039 383.551 19.5469 418.707V456.354H124.723V494ZM58.3652 421.051C75.5039 387.945 93.9609 359.088 124.723 313.971H125.602V422.223H58.3652V421.051ZM301.857 498.688C355.031 498.688 387.258 456.061 387.258 387.799C387.258 319.537 354.738 277.789 301.857 277.789C248.977 277.789 216.311 319.684 216.311 387.945C216.311 456.354 248.684 498.688 301.857 498.688ZM301.857 463.238C276.662 463.238 261.281 435.992 261.281 387.945C261.281 340.338 276.955 313.238 301.857 313.238C326.906 313.238 342.287 340.191 342.287 387.945C342.287 436.139 327.053 463.238 301.857 463.238ZM516.785 494H558.826V456.354H586.365V420.904H558.826V282.623H496.424C453.064 346.49 430.066 383.551 411.609 418.707V456.354H516.785V494ZM450.428 421.051C467.566 387.945 486.023 359.088 516.785 313.971H517.664V422.223H450.428V421.051Z" fill="#ACB5BD"/>
|
||||
</mask>
|
||||
<g mask="url(#mask1_468_2978)">
|
||||
<path d="M250 242.5L376.5 546H647V242.5H250Z" fill="#858E96"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.3 KiB |
4
apps/space/public/project-not-published.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="219" height="219" viewBox="0 0 219 219" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="109.5" cy="109.5" r="109.5" fill="#FAFAFA"/>
|
||||
<path d="M110.423 153.361C104.339 153.361 98.6853 152.27 93.4608 150.087C88.2363 147.904 83.6917 144.88 79.827 141.016C75.9623 137.151 72.9385 132.606 70.7557 127.382C68.5728 122.157 67.4814 116.504 67.4814 110.42C67.4814 105.554 68.1971 100.973 69.6285 96.679C71.0598 92.3849 73.0638 88.4486 75.6402 84.8702L63.9388 73.1687C63.2946 72.5246 62.9905 71.7552 63.0263 70.8606C63.062 69.966 63.402 69.1967 64.0461 68.5525C64.6902 67.9084 65.4596 67.5864 66.3542 67.5864C67.2488 67.5864 68.0182 67.9084 68.6623 68.5525L150.68 150.678C151.324 151.322 151.646 152.073 151.646 152.932C151.646 153.791 151.324 154.542 150.68 155.186C150.036 155.83 149.266 156.153 148.372 156.153C147.477 156.153 146.708 155.83 146.064 155.186L135.973 145.203C132.394 147.779 128.458 149.783 124.164 151.214C119.87 152.646 115.289 153.361 110.423 153.361ZM110.423 146.92C114.359 146.92 118.08 146.366 121.587 145.256C125.094 144.147 128.351 142.59 131.356 140.586L112.355 121.585L106.343 127.597C105.699 128.241 104.948 128.581 104.089 128.617C103.23 128.652 102.478 128.348 101.834 127.704L88.7373 114.5C88.0932 113.855 87.789 113.05 87.8248 112.084C87.8606 111.118 88.2005 110.313 88.8446 109.669C89.4888 109.025 90.2939 108.703 91.2601 108.703C92.2263 108.703 93.0314 109.025 93.6755 109.669L104.089 120.189L107.524 116.754L80.2564 89.4864C78.2525 92.4922 76.6959 95.7486 75.5866 99.2555C74.4772 102.762 73.9226 106.484 73.9226 110.42C73.9226 120.798 77.4116 129.475 84.3895 136.453C91.3674 143.431 100.045 146.92 110.423 146.92ZM145.205 135.97L140.589 131.354C142.593 128.348 144.149 125.092 145.259 121.585C146.368 118.078 146.923 114.356 146.923 110.42C146.923 100.043 143.434 91.365 136.456 84.3871C129.478 77.4092 120.8 73.9202 110.423 73.9202C106.486 73.9202 102.765 74.4748 99.2579 75.5842C95.751 76.6935 92.4946 78.2501 89.4888 80.254L84.8726 75.6378C88.451 73.0614 92.3873 71.0574 96.6814 69.6261C100.976 68.1947 105.556 67.479 110.423 67.479C116.434 67.479 122.052 68.5883 127.277 70.8069C132.502 73.0256 137.046 76.0672 140.911 79.9319C144.776 83.7967 147.817 88.3413 150.036 93.5658C152.254 98.7903 153.364 104.408 153.364 110.42C153.364 115.287 152.648 119.867 151.217 124.161C149.785 128.455 147.781 132.392 145.205 135.97ZM121.695 112.353L116.756 107.522L127.17 97.1084C127.814 96.4643 128.601 96.1422 129.531 96.1422C130.462 96.1422 131.285 96.4643 132.001 97.1084C132.716 97.8241 133.074 98.6471 133.074 99.5775C133.074 100.508 132.716 101.331 132.001 102.047L121.695 112.353Z" fill="#B9B9B9"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
15
setup.sh
@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
cp ./.env.example ./.env
|
||||
# cp ./.env.example ./.env
|
||||
|
||||
# Export for tr error in mac
|
||||
export LC_ALL=C
|
||||
@ -14,3 +14,16 @@ echo -e "SECRET_KEY=\"$(tr -dc 'a-z0-9' < /dev/urandom | head -c50)\"" >> ./.en
|
||||
|
||||
# WEB_URL for email redirection and image saving
|
||||
echo -e "WEB_URL=$1" >> ./.env
|
||||
|
||||
# Generate Prompt for taking tiptap auth key
|
||||
echo -e "\n\e[1;38m Instructions for generating TipTap Pro Extensions Auth Token \e[0m \n"
|
||||
|
||||
echo -e "\e[1;38m 1. Head over to TipTap cloud's Pro Extensions Page, https://collab.tiptap.dev/pro-extensions \e[0m"
|
||||
echo -e "\e[1;38m 2. Copy the token given to you under the first paragraph, after 'Here it is' \e[0m \n"
|
||||
|
||||
read -p $'\e[1;32m Please Enter Your TipTap Pro Extensions Authentication Token: \e[0m \e[1;36m' authToken
|
||||
|
||||
|
||||
echo "@tiptap-pro:registry=https://registry.tiptap.dev/
|
||||
//registry.tiptap.dev/:_authToken=${authToken}" > .npmrc
|
||||
|
||||
|
108
yarn.lock
@ -1384,10 +1384,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.3.2.tgz#fb819366771f5721e9438ca3a42ad18684f0949b"
|
||||
integrity sha512-upwtMaHxlv/udAWGq0kE+rg8huwmcxQPsKZFhS1R5iVO323mvxEBe1YrSXe1awLbg9sTIuEHbgxjLLt7JbeuAQ==
|
||||
|
||||
"@next/env@13.4.13":
|
||||
version "13.4.13"
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-13.4.13.tgz#50250cec7626904b93a4a934933d6a747763259d"
|
||||
integrity sha512-fwz2QgVg08v7ZL7KmbQBLF2PubR/6zQdKBgmHEl3BCyWTEDsAQEijjw2gbFhI1tcKfLdOOJUXntz5vZ4S0Polg==
|
||||
"@next/env@13.4.16":
|
||||
version "13.4.16"
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-13.4.16.tgz#382b565b35a2a69bd0e6b50f74c7b95f0c4b1097"
|
||||
integrity sha512-pCU0sJBqdfKP9mwDadxvZd+eLz3fZrTlmmDHY12Hdpl3DD0vy8ou5HWKVfG0zZS6tqhL4wnQqRbspdY5nqa7MA==
|
||||
|
||||
"@next/eslint-plugin-next@12.2.2":
|
||||
version "12.2.2"
|
||||
@ -1425,20 +1425,20 @@
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.2.tgz#97c532d35c66ce6b6941ae24b5b8b267b9b0d0d8"
|
||||
integrity sha512-PTUfe1ZrwjsiuTmr3bOM9lsoy5DCmfYsLOUF9ZVhtbi5MNJVmUTy4VZ06GfrvnCO5hGCr48z3vpFE9QZ0qLcPw==
|
||||
|
||||
"@next/swc-darwin-arm64@13.4.13":
|
||||
version "13.4.13"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.13.tgz#700fddf66c936c89f98eb60d88cc3d06642aa0bf"
|
||||
integrity sha512-ZptVhHjzUuivnXMNCJ6lER33HN7lC+rZ01z+PM10Ows21NHFYMvGhi5iXkGtBDk6VmtzsbqnAjnx4Oz5um0FjA==
|
||||
"@next/swc-darwin-arm64@13.4.16":
|
||||
version "13.4.16"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.16.tgz#ed6a342f95e5f21213fdadbceb65b40ae678cee0"
|
||||
integrity sha512-Rl6i1uUq0ciRa3VfEpw6GnWAJTSKo9oM2OrkGXPsm7rMxdd2FR5NkKc0C9xzFCI4+QtmBviWBdF2m3ur3Nqstw==
|
||||
|
||||
"@next/swc-darwin-x64@12.3.2":
|
||||
version "12.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.2.tgz#e0cb4ff4b11faaff3a891bd1d18ed72f71e30ebe"
|
||||
integrity sha512-1HkjmS9awwlaeEY8Y01nRSNkSv3y+qnC/mjMPe/W66hEh3QKa/LQHqHeS7NOdEs19B2mhZ7w+EgMRXdLQ0Su8w==
|
||||
|
||||
"@next/swc-darwin-x64@13.4.13":
|
||||
version "13.4.13"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.13.tgz#762d422cb31b27807c9bf4eac766986742a051fe"
|
||||
integrity sha512-t9nTiWCLApw8W4G1kqJyYP7y6/7lyal3PftmRturIxAIBlZss9wrtVN8nci50StDHmIlIDxfguYIEGVr9DbFTg==
|
||||
"@next/swc-darwin-x64@13.4.16":
|
||||
version "13.4.16"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.16.tgz#36c16066a1a3ef8211e84a6a5d72bef15826b291"
|
||||
integrity sha512-o1vIKYbZORyDmTrPV1hApt9NLyWrS5vr2p5hhLGpOnkBY1cz6DAXjv8Lgan8t6X87+83F0EUDlu7klN8ieZ06A==
|
||||
|
||||
"@next/swc-freebsd-x64@12.3.2":
|
||||
version "12.3.2"
|
||||
@ -1455,70 +1455,70 @@
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.2.tgz#26df7d7cdc18cf413f12a408179ee4ac315f383a"
|
||||
integrity sha512-T9GCFyOIb4S3acA9LqflUYD+QZ94iZketHCqKdoO0Nx0OCHIgGJV5rotDe8TDXwh/goYpIfyHU4j1qqw4w4VnA==
|
||||
|
||||
"@next/swc-linux-arm64-gnu@13.4.13":
|
||||
version "13.4.13"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.13.tgz#d567943a0111dcf26de6e5e034874b405057facc"
|
||||
integrity sha512-xEHUqC8eqR5DHe8SOmMnDU1K3ggrJ28uIKltrQAwqFSSSmzjnN/XMocZkcVhuncuxYrpbri0iMQstRyRVdQVWg==
|
||||
"@next/swc-linux-arm64-gnu@13.4.16":
|
||||
version "13.4.16"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.16.tgz#a5b5500737f07e3aa7f184014d8df7973420df26"
|
||||
integrity sha512-JRyAl8lCfyTng4zoOmE6hNI2f1MFUr7JyTYCHl1RxX42H4a5LMwJhDVQ7a9tmDZ/yj+0hpBn+Aan+d6lA3v0UQ==
|
||||
|
||||
"@next/swc-linux-arm64-musl@12.3.2":
|
||||
version "12.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.2.tgz#fd42232a6b10d9f9a4f71433d59c280a4532d06f"
|
||||
integrity sha512-hxNVZS6L3c2z3l9EH2GP0MGQ9exu6O8cohYNZyqC9WUl6C03sEn8xzDH1y+NgD3fVurvYkGU5F0PDddJJLfDIw==
|
||||
|
||||
"@next/swc-linux-arm64-musl@13.4.13":
|
||||
version "13.4.13"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.13.tgz#775f246123b8f1f3726dc14d80c7f7b67bc50cb4"
|
||||
integrity sha512-sNf3MnLAm8rquSSAoeD9nVcdaDeRYOeey4stOWOyWIgbBDtP+C93amSgH/LPTDoUV7gNiU6f+ghepTjTjRgIUQ==
|
||||
"@next/swc-linux-arm64-musl@13.4.16":
|
||||
version "13.4.16"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.16.tgz#381b7662c5b10ed5750dce41dd57841aa0713e77"
|
||||
integrity sha512-9gqVqNzUMWbUDgDiND18xoUqhwSm2gmksqXgCU0qaOKt6oAjWz8cWYjgpPVD0WICKFylEY/gvPEP1fMZDVFZ/g==
|
||||
|
||||
"@next/swc-linux-x64-gnu@12.3.2":
|
||||
version "12.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.2.tgz#5307579e3d8fbdb03adbe6cfc915b51548e0a103"
|
||||
integrity sha512-fCPkLuwDwY8/QeXxciJJjDHG09liZym/Bhb4A+RLFQ877wUkwFsNWDUTSdUx0YXlYK/1gf67BKauqKkOKp6CYw==
|
||||
|
||||
"@next/swc-linux-x64-gnu@13.4.13":
|
||||
version "13.4.13"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.13.tgz#d5fc6441c181bfa09f3cb0285bf3cbb5b111e53b"
|
||||
integrity sha512-WhcRaJJSHyx9OWmKjjz+OWHumiPZWRqmM/09Bt7Up4UqUJFFhGExeztR4trtv3rflvULatu9IH/nTV8fUUgaMA==
|
||||
"@next/swc-linux-x64-gnu@13.4.16":
|
||||
version "13.4.16"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.16.tgz#6e0b0eab1c316506950aeb4a09a5ea5c38edabe7"
|
||||
integrity sha512-KcQGwchAKmZVPa8i5PLTxvTs1/rcFnSltfpTm803Tr/BtBV3AxCkHLfhtoyVtVzx/kl/oue8oS+DSmbepQKwhw==
|
||||
|
||||
"@next/swc-linux-x64-musl@12.3.2":
|
||||
version "12.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.2.tgz#d5cb920a825a8dc80ffba8a6b797fb845af0b84c"
|
||||
integrity sha512-o+GifBIQ2K+/MEFxHsxUZoU3bsuVFLXZYWd3idimFHiVdDCVYiKsY6mYMmKDlucX+9xRyOCkKL9Tjf+3tuXJpw==
|
||||
|
||||
"@next/swc-linux-x64-musl@13.4.13":
|
||||
version "13.4.13"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.13.tgz#6286557e7cc7a0acb3cf0c69e279b3ae2b9a9259"
|
||||
integrity sha512-+Y4LLhOWWZQIDKVwr2R17lq2KSN0F1c30QVgGIWfnjjHpH8nrIWHEndhqYU+iFuW8It78CiJjQKTw4f51HD7jA==
|
||||
"@next/swc-linux-x64-musl@13.4.16":
|
||||
version "13.4.16"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.16.tgz#36b84e4509168a5cadf9dfd728c239002d4311fe"
|
||||
integrity sha512-2RbMZNxYnJmW8EPHVBsGZPq5zqWAyBOc/YFxq/jIQ/Yn3RMFZ1dZVCjtIcsiaKmgh7mjA/W0ApbumutHNxRqqQ==
|
||||
|
||||
"@next/swc-win32-arm64-msvc@12.3.2":
|
||||
version "12.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.2.tgz#2a0d619e5bc0cec17ed093afd1ca6b1c37c2690c"
|
||||
integrity sha512-crii66irzGGMSUR0L8r9+A06eTv7FTXqw4rgzJ33M79EwQJOdpY7RVKXLQMurUhniEeQEEOfamiEdPIi/qxisw==
|
||||
|
||||
"@next/swc-win32-arm64-msvc@13.4.13":
|
||||
version "13.4.13"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.13.tgz#6a50b4b8ee55eb5564c2bd33eefedb9306986b0a"
|
||||
integrity sha512-rWurdOR20uxjfqd1X9vDAgv0Jb26KjyL8akF9CBeFqX8rVaBAnW/Wf6A2gYEwyYY4Bai3T7p1kro6DFrsvBAAw==
|
||||
"@next/swc-win32-arm64-msvc@13.4.16":
|
||||
version "13.4.16"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.16.tgz#52d36f909ccdefa2761617b6d4e9ae65f99880a9"
|
||||
integrity sha512-thDcGonELN7edUKzjzlHrdoKkm7y8IAdItQpRvvMxNUXa4d9r0ElofhTZj5emR7AiXft17hpen+QAkcWpqG7Jg==
|
||||
|
||||
"@next/swc-win32-ia32-msvc@12.3.2":
|
||||
version "12.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.2.tgz#769bef60d0d678c3d7606a4dc7fee018d6199227"
|
||||
integrity sha512-5hRUSvn3MdQ4nVRu1rmKxq5YJzpTtZfaC/NyGw6wa4NSF1noUn/pdQGUr+I5Qz3CZkd1gZzzC0eaXQHlrk0E2g==
|
||||
|
||||
"@next/swc-win32-ia32-msvc@13.4.13":
|
||||
version "13.4.13"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.13.tgz#02e98e1d4cd7a81de58a78044c5f2a5d7fdf4c83"
|
||||
integrity sha512-E8bSPwRuY5ibJ3CzLQmJEt8qaWrPYuUTwnrwygPUEWoLzD5YRx9SD37oXRdU81TgGwDzCxpl7z5Nqlfk50xAog==
|
||||
"@next/swc-win32-ia32-msvc@13.4.16":
|
||||
version "13.4.16"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.16.tgz#a9cb0556d19c33fbb39ac9bef195fd490d6c7673"
|
||||
integrity sha512-f7SE1Mo4JAchUWl0LQsbtySR9xCa+x55C0taetjUApKtcLR3AgAjASrrP+oE1inmLmw573qRnE1eZN8YJfEBQw==
|
||||
|
||||
"@next/swc-win32-x64-msvc@12.3.2":
|
||||
version "12.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.2.tgz#45beb4b9d28e6dd6abf63cab1c5b92dc84323a6b"
|
||||
integrity sha512-tpQJYUH+TzPMIsdVl9fH8uDg47iwiNjKY+8e9da3dXqlkztKzjSw0OwSADoqh3KrifplXeKSta+BBGLdBqg3sg==
|
||||
|
||||
"@next/swc-win32-x64-msvc@13.4.13":
|
||||
version "13.4.13"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.13.tgz#db150b7d84e6218e53e748a6f0ab2159afc2cd6a"
|
||||
integrity sha512-4KlyC6jWRubPnppgfYsNTPeWfGCxtWLh5vaOAW/kdzAk9widqho8Qb5S4K2vHmal1tsURi7Onk2MMCV1phvyqA==
|
||||
"@next/swc-win32-x64-msvc@13.4.16":
|
||||
version "13.4.16"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.16.tgz#79a151d94583e03992c80df3d3e7f7686390ddac"
|
||||
integrity sha512-WamDZm1M/OEM4QLce3lOmD1XdLEl37zYZwlmOLhmF7qYJ2G6oYm9+ejZVv+LakQIsIuXhSpVlOvrxIAHqwRkPQ==
|
||||
|
||||
"@nivo/annotations@0.80.0":
|
||||
version "0.80.0"
|
||||
@ -5884,12 +5884,12 @@ next@12.3.2:
|
||||
"@next/swc-win32-ia32-msvc" "12.3.2"
|
||||
"@next/swc-win32-x64-msvc" "12.3.2"
|
||||
|
||||
next@^13.4.13:
|
||||
version "13.4.13"
|
||||
resolved "https://registry.yarnpkg.com/next/-/next-13.4.13.tgz#8824c5702daa2ef691386871c9158a6324df33d6"
|
||||
integrity sha512-A3YVbVDNeXLhWsZ8Nf6IkxmNlmTNz0yVg186NJ97tGZqPDdPzTrHotJ+A1cuJm2XfuWPrKOUZILl5iBQkIf8Jw==
|
||||
next@^13.4.16:
|
||||
version "13.4.16"
|
||||
resolved "https://registry.yarnpkg.com/next/-/next-13.4.16.tgz#327ef6885b22161ed001cd5943c20b5e409a9406"
|
||||
integrity sha512-1xaA/5DrfpPu0eV31Iro7JfPeqO8uxQWb1zYNTe+KDKdzqkAGapLcDYHMLNKXKB7lHjZ7LfKUOf9dyuzcibrhA==
|
||||
dependencies:
|
||||
"@next/env" "13.4.13"
|
||||
"@next/env" "13.4.16"
|
||||
"@swc/helpers" "0.5.1"
|
||||
busboy "1.6.0"
|
||||
caniuse-lite "^1.0.30001406"
|
||||
@ -5898,15 +5898,15 @@ next@^13.4.13:
|
||||
watchpack "2.4.0"
|
||||
zod "3.21.4"
|
||||
optionalDependencies:
|
||||
"@next/swc-darwin-arm64" "13.4.13"
|
||||
"@next/swc-darwin-x64" "13.4.13"
|
||||
"@next/swc-linux-arm64-gnu" "13.4.13"
|
||||
"@next/swc-linux-arm64-musl" "13.4.13"
|
||||
"@next/swc-linux-x64-gnu" "13.4.13"
|
||||
"@next/swc-linux-x64-musl" "13.4.13"
|
||||
"@next/swc-win32-arm64-msvc" "13.4.13"
|
||||
"@next/swc-win32-ia32-msvc" "13.4.13"
|
||||
"@next/swc-win32-x64-msvc" "13.4.13"
|
||||
"@next/swc-darwin-arm64" "13.4.16"
|
||||
"@next/swc-darwin-x64" "13.4.16"
|
||||
"@next/swc-linux-arm64-gnu" "13.4.16"
|
||||
"@next/swc-linux-arm64-musl" "13.4.16"
|
||||
"@next/swc-linux-x64-gnu" "13.4.16"
|
||||
"@next/swc-linux-x64-musl" "13.4.16"
|
||||
"@next/swc-win32-arm64-msvc" "13.4.16"
|
||||
"@next/swc-win32-ia32-msvc" "13.4.16"
|
||||
"@next/swc-win32-x64-msvc" "13.4.16"
|
||||
|
||||
no-case@^3.0.4:
|
||||
version "3.0.4"
|
||||
|