forked from github/plane
Merge branch 'develop' of github.com:makeplane/plane into chore/api_endpoints
This commit is contained in:
commit
065fee9420
@ -34,7 +34,7 @@ export const SelectProject: React.FC<Props> = ({ value, onChange, projects }) =>
|
|||||||
.join(", ")
|
.join(", ")
|
||||||
: "All projects"
|
: "All projects"
|
||||||
}
|
}
|
||||||
optionsClassName="min-w-full"
|
optionsClassName="min-w-full max-w-[20rem]"
|
||||||
multiple
|
multiple
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -92,7 +92,7 @@ export const GptAssistantModal: React.FC<Props> = (props) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
const error = err?.data?.error;
|
const error = err?.data?.error;
|
||||||
|
|
||||||
if (err.status === 429)
|
if (err?.status === 429)
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "error",
|
type: "error",
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
|
@ -31,6 +31,8 @@ import type { IUser, IIssue, ISearchIssueResponse } from "types";
|
|||||||
// components
|
// components
|
||||||
import { RichTextEditorWithRef } from "@plane/rich-text-editor";
|
import { RichTextEditorWithRef } from "@plane/rich-text-editor";
|
||||||
import useEditorSuggestions from "hooks/use-editor-suggestions";
|
import useEditorSuggestions from "hooks/use-editor-suggestions";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
const aiService = new AIService();
|
const aiService = new AIService();
|
||||||
const fileService = new FileService();
|
const fileService = new FileService();
|
||||||
@ -89,7 +91,7 @@ interface IssueFormProps {
|
|||||||
)[];
|
)[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DraftIssueForm: FC<IssueFormProps> = (props) => {
|
export const DraftIssueForm: FC<IssueFormProps> = observer((props) => {
|
||||||
const {
|
const {
|
||||||
handleFormSubmit,
|
handleFormSubmit,
|
||||||
data,
|
data,
|
||||||
@ -100,30 +102,30 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
createMore,
|
createMore,
|
||||||
setCreateMore,
|
setCreateMore,
|
||||||
status,
|
status,
|
||||||
user,
|
|
||||||
fieldsToShow,
|
fieldsToShow,
|
||||||
handleDiscard,
|
handleDiscard,
|
||||||
} = props;
|
} = props;
|
||||||
|
// states
|
||||||
const [stateModal, setStateModal] = useState(false);
|
const [stateModal, setStateModal] = useState(false);
|
||||||
const [labelModal, setLabelModal] = useState(false);
|
const [labelModal, setLabelModal] = useState(false);
|
||||||
const [parentIssueListModalOpen, setParentIssueListModalOpen] = useState(false);
|
const [parentIssueListModalOpen, setParentIssueListModalOpen] = useState(false);
|
||||||
const [selectedParentIssue, setSelectedParentIssue] = useState<ISearchIssueResponse | null>(null);
|
const [selectedParentIssue, setSelectedParentIssue] = useState<ISearchIssueResponse | null>(null);
|
||||||
|
|
||||||
const [gptAssistantModal, setGptAssistantModal] = useState(false);
|
const [gptAssistantModal, setGptAssistantModal] = useState(false);
|
||||||
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
||||||
|
// hooks
|
||||||
const { setValue: setLocalStorageValue } = useLocalStorage("draftedIssue", {});
|
const { setValue: setLocalStorageValue } = useLocalStorage("draftedIssue", {});
|
||||||
|
const { setToastAlert } = useToast();
|
||||||
|
const editorSuggestions = useEditorSuggestions();
|
||||||
|
// refs
|
||||||
const editorRef = useRef<any>(null);
|
const editorRef = useRef<any>(null);
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
// store
|
||||||
const { setToastAlert } = useToast();
|
const {
|
||||||
|
appConfig: { envConfig },
|
||||||
const editorSuggestions = useEditorSuggestions();
|
} = useMobxStore();
|
||||||
|
// form info
|
||||||
const {
|
const {
|
||||||
formState: { errors, isSubmitting },
|
formState: { errors, isSubmitting },
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -440,21 +442,23 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<GptAssistantModal
|
{envConfig?.has_openai_configured && (
|
||||||
isOpen={gptAssistantModal}
|
<GptAssistantModal
|
||||||
handleClose={() => {
|
isOpen={gptAssistantModal}
|
||||||
setGptAssistantModal(false);
|
handleClose={() => {
|
||||||
// this is done so that the title do not reset after gpt popover closed
|
setGptAssistantModal(false);
|
||||||
reset(getValues());
|
// this is done so that the title do not reset after gpt popover closed
|
||||||
}}
|
reset(getValues());
|
||||||
inset="top-2 left-0"
|
}}
|
||||||
content=""
|
inset="top-2 left-0"
|
||||||
htmlContent={watch("description_html")}
|
content=""
|
||||||
onResponse={(response) => {
|
htmlContent={watch("description_html")}
|
||||||
handleAiAssistance(response);
|
onResponse={(response) => {
|
||||||
}}
|
handleAiAssistance(response);
|
||||||
projectId={projectId}
|
}}
|
||||||
/>
|
projectId={projectId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
@ -623,4 +627,4 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
</form>
|
</form>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -94,28 +94,29 @@ export const IssueForm: FC<IssueFormProps> = observer((props) => {
|
|||||||
fieldsToShow,
|
fieldsToShow,
|
||||||
handleFormDirty,
|
handleFormDirty,
|
||||||
} = props;
|
} = props;
|
||||||
|
// states
|
||||||
const [stateModal, setStateModal] = useState(false);
|
const [stateModal, setStateModal] = useState(false);
|
||||||
const [labelModal, setLabelModal] = useState(false);
|
const [labelModal, setLabelModal] = useState(false);
|
||||||
const [parentIssueListModalOpen, setParentIssueListModalOpen] = useState(false);
|
const [parentIssueListModalOpen, setParentIssueListModalOpen] = useState(false);
|
||||||
const [selectedParentIssue, setSelectedParentIssue] = useState<ISearchIssueResponse | null>(null);
|
const [selectedParentIssue, setSelectedParentIssue] = useState<ISearchIssueResponse | null>(null);
|
||||||
|
|
||||||
const [gptAssistantModal, setGptAssistantModal] = useState(false);
|
const [gptAssistantModal, setGptAssistantModal] = useState(false);
|
||||||
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
||||||
|
// refs
|
||||||
const editorRef = useRef<any>(null);
|
const editorRef = useRef<any>(null);
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
// store
|
||||||
const { user: userStore } = useMobxStore();
|
const {
|
||||||
|
user: userStore,
|
||||||
|
appConfig: { envConfig },
|
||||||
|
} = useMobxStore();
|
||||||
const user = userStore.currentUser;
|
const user = userStore.currentUser;
|
||||||
|
console.log("envConfig", envConfig);
|
||||||
|
// hooks
|
||||||
const editorSuggestion = useEditorSuggestions();
|
const editorSuggestion = useEditorSuggestions();
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
// form info
|
||||||
const {
|
const {
|
||||||
formState: { errors, isSubmitting, isDirty },
|
formState: { errors, isSubmitting, isDirty },
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -396,21 +397,23 @@ export const IssueForm: FC<IssueFormProps> = observer((props) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<GptAssistantModal
|
{envConfig?.has_openai_configured && (
|
||||||
isOpen={gptAssistantModal}
|
<GptAssistantModal
|
||||||
handleClose={() => {
|
isOpen={gptAssistantModal}
|
||||||
setGptAssistantModal(false);
|
handleClose={() => {
|
||||||
// this is done so that the title do not reset after gpt popover closed
|
setGptAssistantModal(false);
|
||||||
reset(getValues());
|
// this is done so that the title do not reset after gpt popover closed
|
||||||
}}
|
reset(getValues());
|
||||||
inset="top-2 left-0"
|
}}
|
||||||
content=""
|
inset="top-2 left-0"
|
||||||
htmlContent={watch("description_html")}
|
content=""
|
||||||
onResponse={(response) => {
|
htmlContent={watch("description_html")}
|
||||||
handleAiAssistance(response);
|
onResponse={(response) => {
|
||||||
}}
|
handleAiAssistance(response);
|
||||||
projectId={projectId}
|
}}
|
||||||
/>
|
projectId={projectId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
|
@ -225,6 +225,7 @@ export const IssueView: FC<IIssueView> = observer((props) => {
|
|||||||
size="sm"
|
size="sm"
|
||||||
prependIcon={<Bell className="h-3 w-3" />}
|
prependIcon={<Bell className="h-3 w-3" />}
|
||||||
variant="outline-primary"
|
variant="outline-primary"
|
||||||
|
className="hover:!bg-custom-primary-100/20"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
issueSubscription && issueSubscription.subscribed
|
issueSubscription && issueSubscription.subscribed
|
||||||
? issueSubscriptionRemove()
|
? issueSubscriptionRemove()
|
||||||
|
@ -33,7 +33,7 @@ import {
|
|||||||
import { CustomDatePicker } from "components/ui";
|
import { CustomDatePicker } from "components/ui";
|
||||||
// icons
|
// icons
|
||||||
import { Bell, CalendarDays, LinkIcon, Plus, Signal, Tag, Trash2, Triangle, User2 } from "lucide-react";
|
import { Bell, CalendarDays, LinkIcon, Plus, Signal, Tag, Trash2, Triangle, User2 } from "lucide-react";
|
||||||
import { ContrastIcon, DiceIcon, DoubleCircleIcon, UserGroupIcon } from "@plane/ui";
|
import { Button, ContrastIcon, DiceIcon, DoubleCircleIcon, UserGroupIcon } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
@ -273,17 +273,18 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
!issueDetail?.assignees.includes(user?.id ?? "") &&
|
!issueDetail?.assignees.includes(user?.id ?? "") &&
|
||||||
!router.pathname.includes("[archivedIssueId]") &&
|
!router.pathname.includes("[archivedIssueId]") &&
|
||||||
(fieldsToShow.includes("all") || fieldsToShow.includes("subscribe")) && (
|
(fieldsToShow.includes("all") || fieldsToShow.includes("subscribe")) && (
|
||||||
<button
|
<Button
|
||||||
type="button"
|
size="sm"
|
||||||
className="rounded-md flex items-center gap-2 border border-custom-primary-100 px-2 py-1 text-xs text-custom-primary-100 shadow-sm duration-300 focus:outline-none"
|
prependIcon={<Bell className="h-3 w-3" />}
|
||||||
|
variant="outline-primary"
|
||||||
|
className="hover:!bg-custom-primary-100/20"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (subscribed) handleUnsubscribe();
|
if (subscribed) handleUnsubscribe();
|
||||||
else handleSubscribe();
|
else handleSubscribe();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Bell className="h-3.5 w-3.5" />
|
|
||||||
{loading ? "Loading..." : subscribed ? "Unsubscribe" : "Subscribe"}
|
{loading ? "Loading..." : subscribed ? "Unsubscribe" : "Subscribe"}
|
||||||
</button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{(fieldsToShow.includes("all") || fieldsToShow.includes("link")) && (
|
{(fieldsToShow.includes("all") || fieldsToShow.includes("link")) && (
|
||||||
<button
|
<button
|
||||||
|
@ -429,10 +429,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
<Disclosure>
|
<Disclosure>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<div className={`relative flex h-full w-full flex-col ${open ? "" : "flex-row"}`}>
|
<div className={`relative flex h-full w-full flex-col ${open ? "" : "flex-row"}`}>
|
||||||
<Disclosure.Button
|
<Disclosure.Button className="flex w-full items-center justify-between gap-2 p-1.5">
|
||||||
className="flex w-full items-center justify-between gap-2 p-1.5"
|
|
||||||
disabled={!isStartValid || !isEndValid}
|
|
||||||
>
|
|
||||||
<div className="flex items-center justify-start gap-2 text-sm">
|
<div className="flex items-center justify-start gap-2 text-sm">
|
||||||
<span className="font-medium text-custom-text-200">Links</span>
|
<span className="font-medium text-custom-text-200">Links</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -168,7 +168,7 @@ export const NotificationCard: React.FC<NotificationCardProps> = (props) => {
|
|||||||
onClick: () => {
|
onClick: () => {
|
||||||
markNotificationReadStatusToggle(notification.id).then(() => {
|
markNotificationReadStatusToggle(notification.id).then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
title: notification.read_at ? "Notification marked as unread" : "Notification marked as read",
|
title: notification.read_at ? "Notification marked as read" : "Notification marked as unread",
|
||||||
type: "success",
|
type: "success",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -19,6 +19,7 @@ import { IUser, IPageBlock } from "types";
|
|||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { PAGE_BLOCKS_LIST } from "constants/fetch-keys";
|
import { PAGE_BLOCKS_LIST } from "constants/fetch-keys";
|
||||||
import useEditorSuggestions from "hooks/use-editor-suggestions";
|
import useEditorSuggestions from "hooks/use-editor-suggestions";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
handleClose: () => void;
|
handleClose: () => void;
|
||||||
@ -40,19 +41,24 @@ const pagesService = new PageService();
|
|||||||
const issueService = new IssueService();
|
const issueService = new IssueService();
|
||||||
const fileService = new FileService();
|
const fileService = new FileService();
|
||||||
|
|
||||||
export const CreateUpdateBlockInline: FC<Props> = ({ handleClose, data, handleAiAssistance, setIsSyncing, focus }) => {
|
export const CreateUpdateBlockInline: FC<Props> = (props) => {
|
||||||
|
const { handleClose, data, handleAiAssistance, setIsSyncing, focus } = props;
|
||||||
|
// states
|
||||||
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
||||||
const [gptAssistantModal, setGptAssistantModal] = useState(false);
|
const [gptAssistantModal, setGptAssistantModal] = useState(false);
|
||||||
|
// store
|
||||||
|
const {
|
||||||
|
appConfig: { envConfig },
|
||||||
|
} = useMobxStore();
|
||||||
|
// refs
|
||||||
const editorRef = useRef<any>(null);
|
const editorRef = useRef<any>(null);
|
||||||
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, pageId } = router.query;
|
const { workspaceSlug, projectId, pageId } = router.query;
|
||||||
|
// hooks
|
||||||
const editorSuggestion = useEditorSuggestions();
|
const editorSuggestion = useEditorSuggestions();
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
// form info
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
@ -222,9 +228,7 @@ export const CreateUpdateBlockInline: FC<Props> = ({ handleClose, data, handleAi
|
|||||||
else handleSubmit(createPageBlock)();
|
else handleSubmit(createPageBlock)();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("keydown", submitForm);
|
window.addEventListener("keydown", submitForm);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener("keydown", submitForm);
|
window.removeEventListener("keydown", submitForm);
|
||||||
};
|
};
|
||||||
@ -345,26 +349,28 @@ export const CreateUpdateBlockInline: FC<Props> = ({ handleClose, data, handleAi
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<GptAssistantModal
|
{envConfig?.has_openai_configured && (
|
||||||
block={data ? data : undefined}
|
<GptAssistantModal
|
||||||
isOpen={gptAssistantModal}
|
block={data ? data : undefined}
|
||||||
handleClose={() => setGptAssistantModal(false)}
|
isOpen={gptAssistantModal}
|
||||||
inset="top-8 left-0"
|
handleClose={() => setGptAssistantModal(false)}
|
||||||
content={watch("description_html")}
|
inset="top-8 left-0"
|
||||||
htmlContent={watch("description_html")}
|
content={watch("description_html")}
|
||||||
onResponse={(response) => {
|
htmlContent={watch("description_html")}
|
||||||
if (data && handleAiAssistance) {
|
onResponse={(response) => {
|
||||||
handleAiAssistance(response);
|
if (data && handleAiAssistance) {
|
||||||
editorRef.current?.setEditorValue(`${watch("description_html")}<p>${response}</p>` ?? "");
|
handleAiAssistance(response);
|
||||||
} else {
|
editorRef.current?.setEditorValue(`${watch("description_html")}<p>${response}</p>` ?? "");
|
||||||
setValue("description", {});
|
} else {
|
||||||
setValue("description_html", `${watch("description_html")}<p>${response}</p>`);
|
setValue("description", {});
|
||||||
|
setValue("description_html", `${watch("description_html")}<p>${response}</p>`);
|
||||||
|
|
||||||
editorRef.current?.setEditorValue(watch("description_html") ?? "");
|
editorRef.current?.setEditorValue(watch("description_html") ?? "");
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
projectId={projectId?.toString() ?? ""}
|
projectId={projectId?.toString() ?? ""}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -113,7 +113,7 @@ export const ProjectCard: React.FC<ProjectCardProps> = observer((props) => {
|
|||||||
className="absolute top-0 left-0 h-full w-full object-cover rounded-t"
|
className="absolute top-0 left-0 h-full w-full object-cover rounded-t"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="absolute h-10 w-full bottom-4 z-10 flex items-center justify-between px-4">
|
<div className="absolute h-10 w-full bottom-4 z-10 flex items-center justify-between gap-3 px-4">
|
||||||
<div className="flex items-center gap-2.5 flex-grow truncate">
|
<div className="flex items-center gap-2.5 flex-grow truncate">
|
||||||
<div className="h-9 w-9 flex item-center justify-center rounded bg-white/90 flex-shrink-0">
|
<div className="h-9 w-9 flex item-center justify-center rounded bg-white/90 flex-shrink-0">
|
||||||
<span className="flex items-center justify-center">
|
<span className="flex items-center justify-center">
|
||||||
|
@ -11,7 +11,7 @@ import { ConfirmProjectMemberRemove } from "components/project";
|
|||||||
// ui
|
// ui
|
||||||
import { CustomSelect, Tooltip } from "@plane/ui";
|
import { CustomSelect, Tooltip } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { ChevronDown, XCircle } from "lucide-react";
|
import { ChevronDown, Dot, XCircle } from "lucide-react";
|
||||||
// constants
|
// constants
|
||||||
import { ROLE } from "constants/workspace";
|
import { ROLE } from "constants/workspace";
|
||||||
// types
|
// types
|
||||||
@ -116,7 +116,15 @@ export const ProjectMemberListItem: React.FC<Props> = observer((props) => {
|
|||||||
) : (
|
) : (
|
||||||
<h4 className="text-sm cursor-default">{member.display_name || member.email}</h4>
|
<h4 className="text-sm cursor-default">{member.display_name || member.email}</h4>
|
||||||
)}
|
)}
|
||||||
<p className="mt-0.5 text-xs text-custom-sidebar-text-300">{member.email ?? member.display_name}</p>
|
<div className="flex items-center">
|
||||||
|
<p className="text-xs text-custom-text-300">{member.display_name}</p>
|
||||||
|
{isAdmin && (
|
||||||
|
<>
|
||||||
|
<Dot height={16} width={16} className="text-custom-text-300" />
|
||||||
|
<p className="text-xs text-custom-text-300">{member.email}</p>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { FC, useState } from "react";
|
import { FC } from "react";
|
||||||
import { ToggleSwitch } from "@plane/ui";
|
import { ToggleSwitch } from "@plane/ui";
|
||||||
import { Pencil, XCircle } from "lucide-react";
|
|
||||||
import { IWebhook } from "types";
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { RootStore } from "store/root";
|
import { RootStore } from "store/root";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
// types
|
||||||
|
import { IWebhook } from "types";
|
||||||
|
|
||||||
interface IWebhookListItem {
|
interface IWebhookListItem {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
|
@ -23,7 +23,10 @@ export const IssuesStats: React.FC<Props> = ({ data }) => {
|
|||||||
<h4 className="text-sm">Issues assigned to you</h4>
|
<h4 className="text-sm">Issues assigned to you</h4>
|
||||||
<h5 className="mt-2 text-2xl font-semibold">
|
<h5 className="mt-2 text-2xl font-semibold">
|
||||||
{data ? (
|
{data ? (
|
||||||
<div className="cursor-pointer" onClick={() => router.push(`/${workspaceSlug}/me/my-issues`)}>
|
<div
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => router.push(`/${workspaceSlug}/workspace-views/assigned`)}
|
||||||
|
>
|
||||||
{data.assigned_issues_count}
|
{data.assigned_issues_count}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
@ -11,7 +11,7 @@ import { ConfirmWorkspaceMemberRemove } from "components/workspace";
|
|||||||
// ui
|
// ui
|
||||||
import { CustomSelect, Tooltip } from "@plane/ui";
|
import { CustomSelect, Tooltip } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { ChevronDown, XCircle } from "lucide-react";
|
import { ChevronDown, Dot, XCircle } from "lucide-react";
|
||||||
// constants
|
// constants
|
||||||
import { ROLE } from "constants/workspace";
|
import { ROLE } from "constants/workspace";
|
||||||
import { TUserWorkspaceRole } from "types";
|
import { TUserWorkspaceRole } from "types";
|
||||||
@ -132,7 +132,15 @@ export const WorkspaceMembersListItem: FC<Props> = (props) => {
|
|||||||
) : (
|
) : (
|
||||||
<h4 className="text-sm cursor-default">{member.display_name || member.email}</h4>
|
<h4 className="text-sm cursor-default">{member.display_name || member.email}</h4>
|
||||||
)}
|
)}
|
||||||
<p className="mt-0.5 text-xs text-custom-sidebar-text-300">{member.email ?? member.display_name}</p>
|
<div className="flex items-center">
|
||||||
|
<p className="text-xs text-custom-text-300">{member.display_name}</p>
|
||||||
|
{isAdmin && (
|
||||||
|
<>
|
||||||
|
<Dot height={16} width={16} className="text-custom-text-300" />
|
||||||
|
<p className="text-xs text-custom-text-300">{member.email}</p>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 text-xs">
|
<div className="flex items-center gap-2 text-xs">
|
||||||
|
@ -56,7 +56,7 @@ export const WorkspaceMembersList: FC<{ searchQuery: string }> = observer(({ sea
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="divide-y-[0.5px] divide-custom-border-200">
|
<div className="divide-y-[0.5px] divide-custom-border-100">
|
||||||
{workspaceMembersWithInvitations.length > 0
|
{workspaceMembersWithInvitations.length > 0
|
||||||
? searchedMembers?.map((member) => <WorkspaceMembersListItem key={member.id} member={member} />)
|
? searchedMembers?.map((member) => <WorkspaceMembersListItem key={member.id} member={member} />)
|
||||||
: null}
|
: null}
|
||||||
|
@ -239,7 +239,7 @@ export const ISSUE_DISPLAY_FILTERS_BY_LAYOUT: {
|
|||||||
filters: ["priority", "state_group", "labels", "start_date", "target_date"],
|
filters: ["priority", "state_group", "labels", "start_date", "target_date"],
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
display_filters: {
|
display_filters: {
|
||||||
group_by: ["state_detail.group", "priority", "project", "labels", null],
|
group_by: ["state_detail.group", "priority", "project", "labels"],
|
||||||
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "priority"],
|
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "priority"],
|
||||||
type: [null, "active", "backlog"],
|
type: [null, "active", "backlog"],
|
||||||
},
|
},
|
||||||
@ -282,7 +282,7 @@ export const ISSUE_DISPLAY_FILTERS_BY_LAYOUT: {
|
|||||||
filters: ["priority", "state_group", "labels", "start_date", "target_date"],
|
filters: ["priority", "state_group", "labels", "start_date", "target_date"],
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
display_filters: {
|
display_filters: {
|
||||||
group_by: ["state_detail.group", "priority", "project", "labels", null],
|
group_by: ["state_detail.group", "priority", "project", "labels"],
|
||||||
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "priority"],
|
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "priority"],
|
||||||
type: [null, "active", "backlog"],
|
type: [null, "active", "backlog"],
|
||||||
},
|
},
|
||||||
|
2
web/types/app.d.ts
vendored
2
web/types/app.d.ts
vendored
@ -11,4 +11,6 @@ export interface IAppConfig {
|
|||||||
slack_client_id: string | null;
|
slack_client_id: string | null;
|
||||||
posthog_api_key: string | null;
|
posthog_api_key: string | null;
|
||||||
posthog_host: string | null;
|
posthog_host: string | null;
|
||||||
|
has_openai_configured: boolean;
|
||||||
|
has_unsplash_configured: boolean;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user