Compare commits

...
31 changed files with 363 additions and 296 deletions
+11 -8
View File
@@ -10,6 +10,7 @@ import { IFormattedInstanceConfiguration, TInstanceGithubAuthenticationConfigura
import { Button, TOAST_TYPE, getButtonStyling, setToast } from "@plane/ui";
// components
import {
CodeBlock,
ConfirmDiscardModal,
ControllerInput,
CopyField,
@@ -102,7 +103,8 @@ export const InstanceGithubConfigForm: FC<Props> = (props) => {
url: originURL,
description: (
<>
We will auto-generate this. Paste this into the Authorized origin URL field{" "}
We will auto-generate this. Paste this into the{" "}
<CodeBlock darkerShade>Authorized origin URL</CodeBlock> field{" "}
<a
tabIndex={-1}
href="https://github.com/settings/applications/new"
@@ -121,7 +123,8 @@ export const InstanceGithubConfigForm: FC<Props> = (props) => {
url: `${originURL}/auth/github/callback/`,
description: (
<>
We will auto-generate this. Paste this into your Authorized Callback URI field{" "}
We will auto-generate this. Paste this into your{" "}
<CodeBlock darkerShade>Authorized Callback URI</CodeBlock> field{" "}
<a
tabIndex={-1}
href="https://github.com/settings/applications/new"
@@ -143,8 +146,8 @@ export const InstanceGithubConfigForm: FC<Props> = (props) => {
.then((response = []) => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success",
message: "Github Configuration Settings updated successfully",
title: "Done!",
message: "Your GitHub authentication is configured. You should test it now.",
});
reset({
GITHUB_CLIENT_ID: response.find((item) => item.key === "GITHUB_CLIENT_ID")?.value,
@@ -170,8 +173,8 @@ export const InstanceGithubConfigForm: FC<Props> = (props) => {
/>
<div className="flex flex-col gap-8">
<div className="grid grid-cols-2 gap-x-12 gap-y-8 w-full">
<div className="flex flex-col gap-y-4 col-span-2 md:col-span-1">
<div className="pt-2 text-xl font-medium">Configuration</div>
<div className="flex flex-col gap-y-4 col-span-2 md:col-span-1 pt-1">
<div className="pt-2.5 text-xl font-medium">GitHub-provided details for Plane</div>
{GITHUB_FORM_FIELDS.map((field) => (
<ControllerInput
key={field.key}
@@ -201,8 +204,8 @@ export const InstanceGithubConfigForm: FC<Props> = (props) => {
</div>
</div>
<div className="col-span-2 md:col-span-1">
<div className="flex flex-col gap-y-4 px-6 py-4 my-2 bg-custom-background-80/60 rounded-lg">
<div className="pt-2 text-xl font-medium">Service provider details</div>
<div className="flex flex-col gap-y-4 px-6 pt-1.5 pb-4 bg-custom-background-80/60 rounded-lg">
<div className="pt-2 text-xl font-medium">Plane-provided details for GitHub</div>
{GITHUB_SERVICE_FIELD.map((field) => (
<CopyField key={field.key} label={field.label} url={field.url} description={field.description} />
))}
+1 -1
View File
@@ -93,7 +93,7 @@ const InstanceGithubAuthenticationPage = observer(() => {
withBorder={false}
/>
</div>
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md p-4">
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-4">
{formattedConfig ? (
<InstanceGithubConfigForm config={formattedConfig} />
) : (
+10 -8
View File
@@ -8,6 +8,7 @@ import { IFormattedInstanceConfiguration, TInstanceGitlabAuthenticationConfigura
import { Button, TOAST_TYPE, getButtonStyling, setToast } from "@plane/ui";
// components
import {
CodeBlock,
ConfirmDiscardModal,
ControllerInput,
CopyField,
@@ -54,7 +55,7 @@ export const InstanceGitlabConfigForm: FC<Props> = (props) => {
label: "Host",
description: (
<>
This is the <b>GitLab host</b> to use for login, <b>including scheme</b>.
This is either https://gitlab.com or the <CodeBlock>domain.tld</CodeBlock> where you host GitLab.
</>
),
placeholder: "https://gitlab.com",
@@ -116,7 +117,8 @@ export const InstanceGitlabConfigForm: FC<Props> = (props) => {
url: `${originURL}/auth/gitlab/callback/`,
description: (
<>
We will auto-generate this. Paste this into the <b>Redirect URI</b> field of your{" "}
We will auto-generate this. Paste this into the{" "}
<CodeBlock darkerShade>Redirect URI</CodeBlock> field of your{" "}
<a
tabIndex={-1}
href="https://docs.gitlab.com/ee/integration/oauth_provider.html"
@@ -139,8 +141,8 @@ export const InstanceGitlabConfigForm: FC<Props> = (props) => {
.then((response = []) => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success",
message: "GitLab Configuration Settings updated successfully",
title: "Done!",
message: "Your GitLab authentication is configured. You should test it now.",
});
reset({
GITLAB_HOST: response.find((item) => item.key === "GITLAB_HOST")?.value,
@@ -167,8 +169,8 @@ export const InstanceGitlabConfigForm: FC<Props> = (props) => {
/>
<div className="flex flex-col gap-8">
<div className="grid grid-cols-2 gap-x-12 gap-y-8 w-full">
<div className="flex flex-col gap-y-4 col-span-2 md:col-span-1">
<div className="pt-2 text-xl font-medium">Configuration</div>
<div className="flex flex-col gap-y-4 col-span-2 md:col-span-1 pt-1">
<div className="pt-2.5 text-xl font-medium">GitLab-provided details for Plane</div>
{GITLAB_FORM_FIELDS.map((field) => (
<ControllerInput
key={field.key}
@@ -198,8 +200,8 @@ export const InstanceGitlabConfigForm: FC<Props> = (props) => {
</div>
</div>
<div className="col-span-2 md:col-span-1">
<div className="flex flex-col gap-y-4 px-6 py-4 my-2 bg-custom-background-80/60 rounded-lg">
<div className="pt-2 text-xl font-medium">Service provider details</div>
<div className="flex flex-col gap-y-4 px-6 pt-1.5 pb-4 bg-custom-background-80/60 rounded-lg">
<div className="pt-2 text-xl font-medium">Plane-provided details for GitLab</div>
{GITLAB_SERVICE_FIELD.map((field) => (
<CopyField key={field.key} label={field.label} url={field.url} description={field.description} />
))}
+1 -1
View File
@@ -80,7 +80,7 @@ const InstanceGitlabAuthenticationPage = observer(() => {
withBorder={false}
/>
</div>
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md p-4">
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-4">
{formattedConfig ? (
<InstanceGitlabConfigForm config={formattedConfig} />
) : (
+11 -8
View File
@@ -9,6 +9,7 @@ import { IFormattedInstanceConfiguration, TInstanceGoogleAuthenticationConfigura
import { Button, TOAST_TYPE, getButtonStyling, setToast } from "@plane/ui";
// components
import {
CodeBlock,
ConfirmDiscardModal,
ControllerInput,
CopyField,
@@ -101,7 +102,8 @@ export const InstanceGoogleConfigForm: FC<Props> = (props) => {
url: originURL,
description: (
<p>
We will auto-generate this. Paste this into your Authorized JavaScript origins field. For this OAuth client{" "}
We will auto-generate this. Paste this into your{" "}
<CodeBlock darkerShade>Authorized JavaScript origins</CodeBlock> field. For this OAuth client{" "}
<a
href="https://console.cloud.google.com/apis/credentials/oauthclient"
target="_blank"
@@ -119,7 +121,8 @@ export const InstanceGoogleConfigForm: FC<Props> = (props) => {
url: `${originURL}/auth/google/callback/`,
description: (
<p>
We will auto-generate this. Paste this into your Authorized Redirect URI field. For this OAuth client{" "}
We will auto-generate this. Paste this into your <CodeBlock darkerShade>Authorized Redirect URI</CodeBlock>{" "}
field. For this OAuth client{" "}
<a
href="https://console.cloud.google.com/apis/credentials/oauthclient"
target="_blank"
@@ -140,8 +143,8 @@ export const InstanceGoogleConfigForm: FC<Props> = (props) => {
.then((response = []) => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success",
message: "Google Configuration Settings updated successfully",
title: "Done!",
message: "Your Google authentication is configured. You should test it now.",
});
reset({
GOOGLE_CLIENT_ID: response.find((item) => item.key === "GOOGLE_CLIENT_ID")?.value,
@@ -167,8 +170,8 @@ export const InstanceGoogleConfigForm: FC<Props> = (props) => {
/>
<div className="flex flex-col gap-8">
<div className="grid grid-cols-2 gap-x-12 gap-y-8 w-full">
<div className="flex flex-col gap-y-4 col-span-2 md:col-span-1">
<div className="pt-2 text-xl font-medium">Configuration</div>
<div className="flex flex-col gap-y-4 col-span-2 md:col-span-1 pt-1">
<div className="pt-2.5 text-xl font-medium">Google-provided details for Plane</div>
{GOOGLE_FORM_FIELDS.map((field) => (
<ControllerInput
key={field.key}
@@ -198,8 +201,8 @@ export const InstanceGoogleConfigForm: FC<Props> = (props) => {
</div>
</div>
<div className="col-span-2 md:col-span-1">
<div className="flex flex-col gap-y-4 px-6 py-4 my-2 bg-custom-background-80/60 rounded-lg">
<div className="pt-2 text-xl font-medium">Service provider details</div>
<div className="flex flex-col gap-y-4 px-6 pt-1.5 pb-4 bg-custom-background-80/60 rounded-lg">
<div className="pt-2 text-xl font-medium">Plane-provided details for Google</div>
{GOOGLE_SERVICE_DETAILS.map((field) => (
<CopyField key={field.key} label={field.label} url={field.url} description={field.description} />
))}
+1 -1
View File
@@ -81,7 +81,7 @@ const InstanceGoogleAuthenticationPage = observer(() => {
withBorder={false}
/>
</div>
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md p-4">
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-4">
{formattedConfig ? (
<InstanceGoogleConfigForm config={formattedConfig} />
) : (
@@ -1,84 +1,48 @@
import { observer } from "mobx-react";
import Image from "next/image";
import { useTheme } from "next-themes";
import { KeyRound, Mails } from "lucide-react";
// types
import { TInstanceAuthenticationMethodKeys, TInstanceAuthenticationModes } from "@plane/types";
// components
import {
AuthenticationMethodCard,
EmailCodesConfiguration,
GithubConfiguration,
GitlabConfiguration,
GoogleConfiguration,
PasswordLoginConfiguration,
} from "@/components/authentication";
TGetBaseAuthenticationModeProps,
TInstanceAuthenticationMethodKeys,
TInstanceAuthenticationModes,
} from "@plane/types";
// components
import { AuthenticationMethodCard } from "@/components/authentication";
// helpers
import { resolveGeneralTheme } from "@/helpers/common.helper";
import { UpgradeButton } from "@/components/common/upgrade-button";
import { getBaseAuthenticationModes } from "@/helpers/authentication.helper";
// images
import githubLightModeImage from "@/public/logos/github-black.png";
import githubDarkModeImage from "@/public/logos/github-white.png";
import GitlabLogo from "@/public/logos/gitlab-logo.svg";
import GoogleLogo from "@/public/logos/google-logo.svg";
import OIDCLogo from "@/public/logos/oidc-logo.png";
import SAMLLogo from "@/public/logos/saml-logo.svg";
export type TAuthenticationModeProps = {
disabled: boolean;
updateConfig: (key: TInstanceAuthenticationMethodKeys, value: string) => void;
};
export type TGetAuthenticationModeProps = {
disabled: boolean;
updateConfig: (key: TInstanceAuthenticationMethodKeys, value: string) => void;
resolvedTheme: string | undefined;
};
// Authentication methods
export const getAuthenticationModes: (props: TGetAuthenticationModeProps) => TInstanceAuthenticationModes[] = ({
export const getAuthenticationModes: (props: TGetBaseAuthenticationModeProps) => TInstanceAuthenticationModes[] = ({
disabled,
updateConfig,
resolvedTheme,
}) => [
...getBaseAuthenticationModes({ disabled, updateConfig, resolvedTheme }),
{
key: "unique-codes",
name: "Unique codes",
description: "Log in or sign up for Plane using codes sent via email. You need to have set up SMTP to use this method.",
icon: <Mails className="h-6 w-6 p-0.5 text-custom-text-300/80" />,
config: <EmailCodesConfiguration disabled={disabled} updateConfig={updateConfig} />,
key: "oidc",
name: "OIDC",
description: "Authenticate your users via the OpenID Connect protocol.",
icon: <Image src={OIDCLogo} height={20} width={20} alt="OIDC Logo" />,
config: <UpgradeButton />,
unavailable: true,
},
{
key: "passwords-login",
name: "Passwords",
description: "Allow members to create accounts with passwords and use it with their email addresses to sign in.",
icon: <KeyRound className="h-6 w-6 p-0.5 text-custom-text-300/80" />,
config: <PasswordLoginConfiguration disabled={disabled} updateConfig={updateConfig} />,
},
{
key: "google",
name: "Google",
description: "Allow members to log in or sign up for Plane with their Google accounts.",
icon: <Image src={GoogleLogo} height={20} width={20} alt="Google Logo" />,
config: <GoogleConfiguration disabled={disabled} updateConfig={updateConfig} />,
},
{
key: "github",
name: "GitHub",
description: "Allow members to log in or sign up for Plane with their GitHub accounts.",
icon: (
<Image
src={resolveGeneralTheme(resolvedTheme) === "dark" ? githubDarkModeImage : githubLightModeImage}
height={20}
width={20}
alt="GitHub Logo"
/>
),
config: <GithubConfiguration disabled={disabled} updateConfig={updateConfig} />,
},
{
key: "gitlab",
name: "GitLab",
description: "Allow members to login or sign up to plane with their GitLab accounts.",
icon: <Image src={GitlabLogo} height={20} width={20} alt="GitLab Logo" />,
config: <GitlabConfiguration disabled={disabled} updateConfig={updateConfig} />,
key: "saml",
name: "SAML",
description: "Authenticate your users via the Security Assertion Markup Language protocol.",
icon: <Image src={SAMLLogo} height={24} width={24} alt="SAML Logo" className="pb-0.5 pl-0.5" />,
config: <UpgradeButton />,
unavailable: true,
},
];
@@ -97,6 +61,7 @@ export const AuthenticationModes: React.FC<TAuthenticationModeProps> = observer(
icon={method.icon}
config={method.config}
disabled={disabled}
unavailable={method.unavailable}
/>
))}
</>
+4 -4
View File
@@ -41,10 +41,10 @@ export const InstanceSidebar: FC<IInstanceSidebar> = observer(() => {
<div
className={`inset-y-0 z-20 flex h-full flex-shrink-0 flex-grow-0 flex-col border-r border-custom-sidebar-border-200 bg-custom-sidebar-background-100 duration-300
fixed md:relative
${isSidebarCollapsed ? "-ml-[280px]" : ""}
sm:${isSidebarCollapsed ? "-ml-[280px]" : ""}
md:ml-0 ${isSidebarCollapsed ? "w-[70px]" : "w-[280px]"}
lg:ml-0 ${isSidebarCollapsed ? "w-[70px]" : "w-[280px]"}
${isSidebarCollapsed ? "-ml-[290px]" : ""}
sm:${isSidebarCollapsed ? "-ml-[290px]" : ""}
md:ml-0 ${isSidebarCollapsed ? "w-[70px]" : "w-[290px]"}
lg:ml-0 ${isSidebarCollapsed ? "w-[70px]" : "w-[290px]"}
`}
>
<div ref={ref} className="flex h-full w-full flex-1 flex-col">
@@ -11,10 +11,11 @@ type Props = {
config: JSX.Element;
disabled?: boolean;
withBorder?: boolean;
unavailable?: boolean;
};
export const AuthenticationMethodCard: FC<Props> = (props) => {
const { name, description, icon, config, disabled = false, withBorder = true } = props;
const { name, description, icon, config, disabled = false, withBorder = true, unavailable = false } = props;
return (
<div
@@ -22,7 +23,11 @@ export const AuthenticationMethodCard: FC<Props> = (props) => {
"px-4 py-3 border border-custom-border-200": withBorder,
})}
>
<div className="flex grow items-center gap-4">
<div
className={cn("flex grow items-center gap-4", {
"opacity-50": unavailable,
})}
>
<div className="shrink-0">
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-custom-background-80">{icon}</div>
</div>
@@ -0,0 +1,21 @@
import { cn } from "@/helpers/common.helper";
type TProps = {
children: React.ReactNode;
className?: string;
darkerShade?: boolean;
};
export const CodeBlock = ({ children, className, darkerShade }: TProps) => (
<span
className={cn(
"px-0.5 text-xs text-custom-text-300 bg-custom-background-90 font-semibold rounded-md border border-custom-border-100",
{
"text-custom-text-200 bg-custom-background-80 border-custom-border-200": darkerShade,
},
className
)}
>
{children}
</span>
);
@@ -38,7 +38,7 @@ export const ControllerInput: React.FC<Props> = (props) => {
return (
<div className="flex flex-col gap-1">
<h4 className="text-sm text-custom-text-300">
{label} {!required && "(optional)"}
{label}
</h4>
<div className="relative">
<Controller
@@ -80,7 +80,7 @@ export const ControllerInput: React.FC<Props> = (props) => {
</button>
))}
</div>
{description && <p className="text-xs text-custom-text-300">{description}</p>}
{description && <p className="pt-0.5 text-xs text-custom-text-300">{description}</p>}
</div>
);
};
+2
View File
@@ -7,3 +7,5 @@ export * from "./banner";
export * from "./empty-state";
export * from "./logo-spinner";
export * from "./page-header";
export * from "./code-block";
export * from "./upgrade-button";
@@ -0,0 +1,16 @@
"use client";
import React from "react";
// icons
import { SquareArrowOutUpRight } from "lucide-react";
// ui
import { getButtonStyling } from "@plane/ui";
// helpers
import { cn } from "@/helpers/common.helper";
export const UpgradeButton: React.FC = () => (
<a href="https://plane.so/one" target="_blank" className={cn(getButtonStyling("primary", "sm"))}>
Available on One
<SquareArrowOutUpRight className="h-3.5 w-3.5 p-0.5" />
</a>
);
+68 -1
View File
@@ -1,7 +1,24 @@
import { ReactNode } from "react";
import Image from "next/image";
import Link from "next/link";
import { KeyRound, Mails } from "lucide-react";
// types
import { TGetBaseAuthenticationModeProps, TInstanceAuthenticationModes } from "@plane/types";
// components
import {
EmailCodesConfiguration,
GithubConfiguration,
GitlabConfiguration,
GoogleConfiguration,
PasswordLoginConfiguration,
} from "@/components/authentication";
// helpers
import { SUPPORT_EMAIL } from "./common.helper";
import { SUPPORT_EMAIL, resolveGeneralTheme } from "@/helpers/common.helper";
// images
import githubLightModeImage from "@/public/logos/github-black.png";
import githubDarkModeImage from "@/public/logos/github-white.png";
import GitlabLogo from "@/public/logos/gitlab-logo.svg";
import GoogleLogo from "@/public/logos/google-logo.svg";
export enum EPageTypes {
PUBLIC = "PUBLIC",
@@ -134,3 +151,53 @@ export const authErrorHandler = (
return undefined;
};
export const getBaseAuthenticationModes: (props: TGetBaseAuthenticationModeProps) => TInstanceAuthenticationModes[] = ({
disabled,
updateConfig,
resolvedTheme,
}) => [
{
key: "unique-codes",
name: "Unique codes",
description:
"Log in or sign up for Plane using codes sent via email. You need to have set up SMTP to use this method.",
icon: <Mails className="h-6 w-6 p-0.5 text-custom-text-300/80" />,
config: <EmailCodesConfiguration disabled={disabled} updateConfig={updateConfig} />,
},
{
key: "passwords-login",
name: "Passwords",
description: "Allow members to create accounts with passwords and use it with their email addresses to sign in.",
icon: <KeyRound className="h-6 w-6 p-0.5 text-custom-text-300/80" />,
config: <PasswordLoginConfiguration disabled={disabled} updateConfig={updateConfig} />,
},
{
key: "google",
name: "Google",
description: "Allow members to log in or sign up for Plane with their Google accounts.",
icon: <Image src={GoogleLogo} height={20} width={20} alt="Google Logo" />,
config: <GoogleConfiguration disabled={disabled} updateConfig={updateConfig} />,
},
{
key: "github",
name: "GitHub",
description: "Allow members to log in or sign up for Plane with their GitHub accounts.",
icon: (
<Image
src={resolveGeneralTheme(resolvedTheme) === "dark" ? githubDarkModeImage : githubLightModeImage}
height={20}
width={20}
alt="GitHub Logo"
/>
),
config: <GithubConfiguration disabled={disabled} updateConfig={updateConfig} />,
},
{
key: "gitlab",
name: "GitLab",
description: "Allow members to log in or sign up to plane with their GitLab accounts.",
icon: <Image src={GitlabLogo} height={20} width={20} alt="GitLab Logo" />,
config: <GitlabConfiguration disabled={disabled} updateConfig={updateConfig} />,
},
];
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="none">
<g fill="#C22E33">
<path d="M7.754 2l.463.41c.343.304.687.607 1.026.915C11.44 5.32 13.3 7.565 14.7 10.149c.072.132.137.268.202.403l.098.203-.108.057-.081-.115-.21-.299-.147-.214c-1.019-1.479-2.04-2.96-3.442-4.145a6.563 6.563 0 00-1.393-.904c-1.014-.485-1.916-.291-2.69.505-.736.757-1.118 1.697-1.463 2.653-.045.123-.092.245-.139.367l-.082.215-.172-.055c.1-.348.192-.698.284-1.049.21-.795.42-1.59.712-2.356.31-.816.702-1.603 1.093-2.39.169-.341.338-.682.5-1.025h.092z"/>
<path d="M8.448 11.822c-1.626.77-5.56 1.564-7.426 1.36C.717 11.576 3.71 4.05 5.18 2.91l-.095.218a4.638 4.638 0 01-.138.303l-.066.129c-.76 1.462-1.519 2.926-1.908 4.53a7.482 7.482 0 00-.228 1.689c-.01 1.34.824 2.252 2.217 2.309.67.027 1.347-.043 2.023-.114.294-.03.587-.061.88-.084.108-.008.214-.021.352-.039l.231-.028z"/>
<path d="M3.825 14.781c-.445.034-.89.068-1.333.108 4.097.39 8.03-.277 11.91-1.644-1.265-2.23-2.97-3.991-4.952-5.522.026.098.084.169.141.239l.048.06c.17.226.348.448.527.67.409.509.818 1.018 1.126 1.578.778 1.42.356 2.648-1.168 3.296-1.002.427-2.097.718-3.18.892-1.03.164-2.075.243-3.119.323z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+7
View File
@@ -4,6 +4,7 @@ export type TInstanceAuthenticationModes = {
description: string;
icon: JSX.Element;
config: JSX.Element;
unavailable?: boolean;
};
export type TInstanceAuthenticationMethodKeys =
@@ -35,3 +36,9 @@ type TInstanceAuthenticationConfigurationKeys =
export type TInstanceAuthenticationKeys =
| TInstanceAuthenticationMethodKeys
| TInstanceAuthenticationConfigurationKeys;
export type TGetBaseAuthenticationModeProps = {
disabled: boolean;
updateConfig: (key: TInstanceAuthenticationMethodKeys, value: string) => void;
resolvedTheme: string | undefined;
};
@@ -47,11 +47,8 @@ export const IssueModuleSelect: React.FC<TIssueModuleSelect> = observer((props)
modulesToAdd.push(moduleId);
}
}
if (modulesToRemove.length > 0)
await issueOperations.removeModulesFromIssue?.(workspaceSlug, projectId, issueId, modulesToRemove);
if (modulesToAdd.length > 0)
await issueOperations.addModulesToIssue?.(workspaceSlug, projectId, issueId, modulesToAdd);
await issueOperations.changeModulesInIssue?.(workspaceSlug, projectId, issueId, modulesToAdd, modulesToRemove);
setIsUpdating(false);
};
@@ -32,18 +32,18 @@ export type TIssueOperations = {
addCycleToIssue?: (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => Promise<void>;
addIssueToCycle?: (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) => Promise<void>;
removeIssueFromCycle?: (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => Promise<void>;
addModulesToIssue?: (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => Promise<void>;
removeIssueFromModule?: (
workspaceSlug: string,
projectId: string,
moduleId: string,
issueId: string
) => Promise<void>;
removeModulesFromIssue?: (
changeModulesInIssue?: (
workspaceSlug: string,
projectId: string,
issueId: string,
moduleIds: string[]
addModuleIds: string[],
removeModuleIds: string[]
) => Promise<void>;
};
@@ -70,9 +70,8 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
addCycleToIssue,
addIssueToCycle,
removeIssueFromCycle,
addModulesToIssue,
changeModulesInIssue,
removeIssueFromModule,
removeModulesFromIssue,
} = useIssueDetail();
const {
issues: { removeIssue: removeArchivedIssue },
@@ -258,35 +257,6 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
});
}
},
addModulesToIssue: async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => {
try {
const response = await addModulesToIssue(workspaceSlug, projectId, issueId, moduleIds);
captureIssueEvent({
eventName: ISSUE_UPDATED,
payload: { ...response, state: "SUCCESS", element: "Issue detail page" },
updates: {
changed_property: "module_id",
change_details: moduleIds,
},
path: pathname,
});
} catch (error) {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Issue could not be added to the module. Please try again.",
});
captureIssueEvent({
eventName: ISSUE_UPDATED,
payload: { id: issueId, state: "FAILED", element: "Issue detail page" },
updates: {
changed_property: "module_id",
change_details: moduleIds,
},
path: pathname,
});
}
},
removeIssueFromModule: async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
try {
const removeFromModulePromise = removeIssueFromModule(workspaceSlug, projectId, moduleId, issueId);
@@ -323,25 +293,24 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
});
}
},
removeModulesFromIssue: async (
changeModulesInIssue: async (
workspaceSlug: string,
projectId: string,
issueId: string,
moduleIds: string[]
addModuleIds: string[],
removeModuleIds: string[]
) => {
const removeModulesFromIssuePromise = removeModulesFromIssue(workspaceSlug, projectId, issueId, moduleIds);
setPromiseToast(removeModulesFromIssuePromise, {
loading: "Removing module from issue...",
success: {
title: "Success!",
message: () => "Module removed from issue successfully",
},
error: {
title: "Error!",
message: () => "Module remove from issue failed",
const promise = await changeModulesInIssue(workspaceSlug, projectId, issueId, addModuleIds, removeModuleIds);
captureIssueEvent({
eventName: ISSUE_UPDATED,
payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" },
updates: {
changed_property: "module_id",
change_details: { addModuleIds, removeModuleIds },
},
path: pathname,
});
await removeModulesFromIssuePromise;
return promise;
},
}),
[
@@ -353,9 +322,8 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
removeArchivedIssue,
addIssueToCycle,
removeIssueFromCycle,
addModulesToIssue,
changeModulesInIssue,
removeIssueFromModule,
removeModulesFromIssue,
captureIssueEvent,
pathname,
]
@@ -13,6 +13,7 @@ import { EIssuesStoreType } from "@/constants/issue";
import { EUserProjectRoles } from "@/constants/project";
// hooks
import { useEventTracker, useIssueDetail, useIssues, useUser } from "@/hooks/store";
import { useIssuesStore } from "@/hooks/use-issue-layout-store";
interface IIssuePeekOverview {
embedIssue?: boolean;
@@ -55,19 +56,10 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
} = useIssues(EIssuesStoreType.ARCHIVED);
const {
peekIssue,
updateIssue,
removeIssue,
archiveIssue,
issue: { fetchIssue },
} = useIssueDetail();
const {
addCycleToIssue,
addIssueToCycle,
removeIssueFromCycle,
addModulesToIssue,
removeIssueFromModule,
removeModulesFromIssue,
} = useIssueDetail();
const { issues } = useIssuesStore();
const { captureIssueEvent } = useEventTracker();
// state
const [loader, setLoader] = useState(true);
@@ -94,7 +86,8 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
}
},
update: async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => {
await updateIssue(workspaceSlug, projectId, issueId, data)
await issues
?.updateIssue(workspaceSlug, projectId, issueId, data)
.then(() => {
captureIssueEvent({
eventName: ISSUE_UPDATED,
@@ -121,7 +114,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
},
remove: async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
removeIssue(workspaceSlug, projectId, issueId);
issues?.removeIssue(workspaceSlug, projectId, issueId);
setToast({
title: "Success!",
type: TOAST_TYPE.SUCCESS,
@@ -147,7 +140,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
},
archive: async (workspaceSlug: string, projectId: string, issueId: string) => {
try {
await archiveIssue(workspaceSlug, projectId, issueId);
issues?.archiveIssue && (await issues.archiveIssue(workspaceSlug, projectId, issueId));
captureIssueEvent({
eventName: ISSUE_ARCHIVED,
payload: { id: issueId, state: "SUCCESS", element: "Issue peek-overview" },
@@ -189,8 +182,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
},
addCycleToIssue: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
try {
console.log("Peek adding...");
await addCycleToIssue(workspaceSlug, projectId, cycleId, issueId);
await issues.addCycleToIssue(workspaceSlug, projectId, cycleId, issueId);
captureIssueEvent({
eventName: ISSUE_UPDATED,
payload: { issueId, state: "SUCCESS", element: "Issue peek-overview" },
@@ -219,7 +211,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
},
addIssueToCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) => {
try {
await addIssueToCycle(workspaceSlug, projectId, cycleId, issueIds);
await issues.addIssueToCycle(workspaceSlug, projectId, cycleId, issueIds);
captureIssueEvent({
eventName: ISSUE_UPDATED,
payload: { ...issueIds, state: "SUCCESS", element: "Issue peek-overview" },
@@ -248,7 +240,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
},
removeIssueFromCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
try {
const removeFromCyclePromise = removeIssueFromCycle(workspaceSlug, projectId, cycleId, issueId);
const removeFromCyclePromise = issues.removeIssueFromCycle(workspaceSlug, projectId, cycleId, issueId);
setPromiseToast(removeFromCyclePromise, {
loading: "Removing issue from the cycle...",
success: {
@@ -282,38 +274,34 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
});
}
},
addModulesToIssue: async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => {
try {
const response = await addModulesToIssue(workspaceSlug, projectId, issueId, moduleIds);
captureIssueEvent({
eventName: ISSUE_UPDATED,
payload: { ...response, state: "SUCCESS", element: "Issue peek-overview" },
updates: {
changed_property: "module_id",
change_details: moduleIds,
},
path: pathname,
});
} catch (error) {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
message: "Issue could not be added to the module. Please try again.",
});
captureIssueEvent({
eventName: ISSUE_UPDATED,
payload: { id: issueId, state: "FAILED", element: "Issue peek-overview" },
updates: {
changed_property: "module_id",
change_details: moduleIds,
},
path: pathname,
});
}
changeModulesInIssue: async (
workspaceSlug: string,
projectId: string,
issueId: string,
addModuleIds: string[],
removeModuleIds: string[]
) => {
const promise = await issues.changeModulesInIssue(
workspaceSlug,
projectId,
issueId,
addModuleIds,
removeModuleIds
);
captureIssueEvent({
eventName: ISSUE_UPDATED,
payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" },
updates: {
changed_property: "module_id",
change_details: { addModuleIds, removeModuleIds },
},
path: pathname,
});
return promise;
},
removeIssueFromModule: async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
try {
const removeFromModulePromise = removeIssueFromModule(workspaceSlug, projectId, moduleId, issueId);
const removeFromModulePromise = issues.removeIssuesFromModule(workspaceSlug, projectId, moduleId, [issueId]);
setPromiseToast(removeFromModulePromise, {
loading: "Removing issue from the module...",
success: {
@@ -347,43 +335,8 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
});
}
},
removeModulesFromIssue: async (
workspaceSlug: string,
projectId: string,
issueId: string,
moduleIds: string[]
) => {
const removeModulesFromIssuePromise = removeModulesFromIssue(workspaceSlug, projectId, issueId, moduleIds);
setPromiseToast(removeModulesFromIssuePromise, {
loading: "Removing module from issue...",
success: {
title: "Success!",
message: () => "Module removed from issue successfully",
},
error: {
title: "Error!",
message: () => "Module remove from issue failed",
},
});
await removeModulesFromIssuePromise;
},
}),
[
is_archived,
is_draft,
fetchIssue,
updateIssue,
removeIssue,
archiveIssue,
restoreIssue,
addIssueToCycle,
removeIssueFromCycle,
addModulesToIssue,
removeIssueFromModule,
removeModulesFromIssue,
captureIssueEvent,
pathname,
]
[is_archived, is_draft, fetchIssue, issues, restoreIssue, captureIssueEvent, pathname]
);
useEffect(() => {
+39 -6
View File
@@ -1,6 +1,13 @@
import { action, makeObservable, runInAction } from "mobx";
// base class
import { TLoader, IssuePaginationOptions, TIssuesResponse, ViewFlags, TBulkOperationsPayload } from "@plane/types";
import {
TLoader,
IssuePaginationOptions,
TIssuesResponse,
ViewFlags,
TBulkOperationsPayload,
TIssue,
} from "@plane/types";
// services
// types
import { BaseIssuesStore, IBaseIssuesStore } from "../helpers/base-issues.store";
@@ -29,12 +36,13 @@ export interface IArchivedIssues extends IBaseIssuesStore {
subGroupId?: string
) => Promise<TIssuesResponse | undefined>;
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
restoreIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
removeBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
quickAddIssue: (workspaceSlug: string, projectId: string, data: TIssue, id?: string) => Promise<TIssue | undefined>;
bulkUpdateProperties: (workspaceSlug: string, projectId: string, data: TBulkOperationsPayload) => Promise<void>;
archiveBulkIssues: undefined;
quickAddIssue: undefined;
archiveBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
}
export class ArchivedIssues extends BaseIssuesStore implements IArchivedIssues {
@@ -192,6 +200,31 @@ export class ArchivedIssues extends BaseIssuesStore implements IArchivedIssues {
}
};
archiveBulkIssues = undefined;
quickAddIssue = undefined;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
override updateIssue(
workspaceSlug: string,
projectId: string,
issueId: string,
data: Partial<TIssue>,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldSync = true
) {
console.warn("Archived Issues cannot be updated");
return Promise.resolve();
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
override archiveIssue(workspaceSlug: string, projectId: string, issueId: string) {
console.warn("Archived Issues cannot be archived");
return Promise.resolve();
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
override archiveBulkIssues(workspaceSlug: string, projectId: string, issueIds: string[]) {
console.warn("Archived Issues cannot be archived");
return Promise.resolve();
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
override quickAddIssue(workspaceSlug: string, projectId: string, data: TIssue, id?: string) {
console.warn("cannot quick Add Archived issues");
return Promise.resolve(undefined);
}
}
+5 -5
View File
@@ -370,7 +370,9 @@ export class CycleIssues extends BaseIssuesStore implements ICycleIssues {
set(this.activeCycleIds, [cycleId, "nextCursor"], response.next_cursor);
set(this.activeCycleIds, [cycleId, "nextPageResults"], response.next_page_results);
set(this.activeCycleIds, [cycleId, "issueCount"], response.total_count);
update(this.activeCycleIds, [cycleId, "issueIds"], (issueIds: string[] = []) => this.issuesSortWithOrderBy(uniq(concat(issueIds, activeIssueIds)), this.orderBy));
update(this.activeCycleIds, [cycleId, "issueIds"], (issueIds: string[] = []) =>
this.issuesSortWithOrderBy(uniq(concat(issueIds, activeIssueIds)), this.orderBy)
);
return response;
} catch (error) {
@@ -386,7 +388,7 @@ export class CycleIssues extends BaseIssuesStore implements ICycleIssues {
* @param cycleId
* @returns
*/
quickAddIssue = async (workspaceSlug: string, projectId: string, data: TIssue, cycleId: string) => {
override async quickAddIssue(workspaceSlug: string, projectId: string, data: TIssue, cycleId: string) {
try {
// add temporary issue to store list
this.addIssue(data);
@@ -411,7 +413,5 @@ export class CycleIssues extends BaseIssuesStore implements ICycleIssues {
} catch (error) {
throw error;
}
};
archiveBulkIssues = this.bulkArchiveIssues;
}
}
+18 -4
View File
@@ -35,8 +35,9 @@ export interface IDraftIssues extends IBaseIssuesStore {
removeBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
bulkUpdateProperties: (workspaceSlug: string, projectId: string, data: TBulkOperationsPayload) => Promise<void>;
archiveBulkIssues: undefined;
quickAddIssue: undefined;
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
quickAddIssue: (workspaceSlug: string, projectId: string, data: TIssue, id?: string) => Promise<TIssue | undefined>;
archiveBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
}
export class DraftIssues extends BaseIssuesStore implements IDraftIssues {
@@ -167,6 +168,19 @@ export class DraftIssues extends BaseIssuesStore implements IDraftIssues {
createIssue = this.createDraftIssue;
updateIssue = this.updateDraftIssue;
archiveBulkIssues = undefined;
quickAddIssue = undefined;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
override archiveIssue(workspaceSlug: string, projectId: string, issueId: string) {
console.warn("Archived Issues cannot be archived");
return Promise.resolve();
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
override archiveBulkIssues(workspaceSlug: string, projectId: string, issueIds: string[]) {
console.warn("Archived Issues cannot be archived");
return Promise.resolve();
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
override quickAddIssue(workspaceSlug: string, projectId: string, data: TIssue, id?: string) {
console.warn("cannot quick Add Archived issues");
return Promise.resolve(undefined);
}
}
@@ -63,7 +63,7 @@ export interface IBaseIssuesStore {
issuePaginationData: TIssuePaginationData; // map of groupId/subgroup and pagination Data of that particular group/subgroup
//actions
removeIssue(workspaceSlug: string, projectId: string, issueId: string): Promise<void>;
removeIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
// helper methods
getIssueIds: (groupId?: string, subGroupId?: string) => string[] | undefined;
issuesSortWithOrderBy(issueIds: string[], key: Partial<TIssueOrderByOptions>): string[];
@@ -223,11 +223,11 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore {
updateIssue: action,
createDraftIssue: action,
updateDraftIssue: action,
issueQuickAdd: action.bound,
quickAddIssue: action.bound,
removeIssue: action.bound,
archiveIssue: action.bound,
removeBulkIssues: action.bound,
bulkArchiveIssues: action.bound,
archiveBulkIssues: action.bound,
bulkUpdateProperties: action.bound,
addIssueToCycle: action.bound,
@@ -684,8 +684,10 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore {
* @param data
* @returns
*/
async issueQuickAdd(workspaceSlug: string, projectId: string, data: TIssue) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async quickAddIssue(workspaceSlug: string, projectId: string, data: TIssue, id?: string) {
try {
if (!data) return;
// Add issue to store with a temporary Id
this.addIssue(data);
@@ -753,7 +755,7 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore {
* @param projectId
* @param issueIds
*/
bulkArchiveIssues = async (workspaceSlug: string, projectId: string, issueIds: string[]) => {
async archiveBulkIssues(workspaceSlug: string, projectId: string, issueIds: string[]) {
try {
const response = await this.issueService.bulkArchiveIssues(workspaceSlug, projectId, { issue_ids: issueIds });
@@ -774,7 +776,7 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore {
} catch (error) {
throw error;
}
};
}
/**
* @description bulk update properties of selected issues
@@ -1173,8 +1175,8 @@ export abstract class BaseIssuesStore implements IBaseIssuesStore {
const issueId = issue?.id ?? issueBeforeUpdate?.id;
if (!issueId) return;
// get issueUpdates from another method by passing down the three arguments
// issueUpdates is nothing but an array of objects that contain the path of the issueId list that need updating and also the action that needs to be performed at the path
// get updateIssues from another method by passing down the three arguments
// updateIssues is nothing but an array of objects that contain the path of the issueId list that need updating and also the action that needs to be performed at the path
const issueUpdates = this.getUpdateDetails(issue, issueBeforeUpdate, action);
const accumulatedUpdatesForCount = {};
runInAction(() => {
@@ -21,12 +21,12 @@ export interface IIssueStoreActions {
addCycleToIssue: (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => Promise<void>;
addIssueToCycle: (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) => Promise<void>;
removeIssueFromCycle: (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => Promise<void>;
addModulesToIssue: (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => Promise<any>;
removeModulesFromIssue: (
changeModulesInIssue: (
workspaceSlug: string,
projectId: string,
issueId: string,
moduleIds: string[]
addModuleIds: string[],
removeModuleIds: string[]
) => Promise<void>;
removeIssueFromModule: (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => Promise<void>;
}
@@ -193,29 +193,21 @@ export class IssueStore implements IIssueStore {
return cycle;
};
addModulesToIssue = async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => {
const currentModule = await this.rootIssueDetailStore.rootIssueStore.moduleIssues.changeModulesInIssue(
changeModulesInIssue = async (
workspaceSlug: string,
projectId: string,
issueId: string,
addModuleIds: string[],
removeModuleIds: string[]
) => {
await this.rootIssueDetailStore.rootIssueStore.moduleIssues.changeModulesInIssue(
workspaceSlug,
projectId,
issueId,
moduleIds,
[]
);
if (moduleIds && moduleIds.length > 0)
await this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
return currentModule;
};
removeModulesFromIssue = async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => {
const currentModule = await this.rootIssueDetailStore.rootIssueStore.moduleIssues.changeModulesInIssue(
workspaceSlug,
projectId,
issueId,
[],
moduleIds
addModuleIds,
removeModuleIds
);
await this.rootIssueDetailStore.activity.fetchActivities(workspaceSlug, projectId, issueId);
return currentModule;
};
removeIssueFromModule = async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
@@ -198,10 +198,13 @@ export class IssueDetail implements IIssueDetail {
this.issue.addIssueToCycle(workspaceSlug, projectId, cycleId, issueIds);
removeIssueFromCycle = async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) =>
this.issue.removeIssueFromCycle(workspaceSlug, projectId, cycleId, issueId);
addModulesToIssue = async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) =>
this.issue.addModulesToIssue(workspaceSlug, projectId, issueId, moduleIds);
removeModulesFromIssue = async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) =>
this.issue.removeModulesFromIssue(workspaceSlug, projectId, issueId, moduleIds);
changeModulesInIssue = async (
workspaceSlug: string,
projectId: string,
issueId: string,
addModuleIds: string[],
removeModuleIds: string[]
) => this.issue.changeModulesInIssue(workspaceSlug, projectId, issueId, addModuleIds, removeModuleIds);
removeIssueFromModule = async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) =>
this.issue.removeIssueFromModule(workspaceSlug, projectId, moduleId, issueId);
+2 -4
View File
@@ -225,7 +225,7 @@ export class ModuleIssues extends BaseIssuesStore implements IModuleIssues {
* @param moduleId
* @returns
*/
quickAddIssue = async (workspaceSlug: string, projectId: string, data: TIssue, moduleId: string) => {
override async quickAddIssue(workspaceSlug: string, projectId: string, data: TIssue, moduleId: string) {
try {
// add temporary issue to store list
this.addIssue(data);
@@ -249,7 +249,5 @@ export class ModuleIssues extends BaseIssuesStore implements IModuleIssues {
} catch (error) {
throw error;
}
};
archiveBulkIssues = this.bulkArchiveIssues;
}
}
+6 -4
View File
@@ -41,8 +41,7 @@ export interface IProfileIssues extends IBaseIssuesStore {
removeBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
archiveBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
bulkUpdateProperties: (workspaceSlug: string, projectId: string, data: TBulkOperationsPayload) => Promise<void>;
quickAddIssue: undefined;
quickAddIssue: (workspaceSlug: string, projectId: string, data: TIssue, id?: string) => Promise<TIssue | undefined>;
}
export class ProfileIssues extends BaseIssuesStore implements IProfileIssues {
@@ -208,6 +207,9 @@ export class ProfileIssues extends BaseIssuesStore implements IProfileIssues {
return await this.fetchIssues(workspaceSlug, userId, loadType, this.paginationOptions, this.currentView, true);
};
archiveBulkIssues = this.bulkArchiveIssues;
quickAddIssue = undefined;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
override quickAddIssue(workspaceSlug: string, projectId: string, data: TIssue, id?: string) {
console.warn("cannot quick Add to Profile issues");
return Promise.resolve(undefined);
}
}
@@ -173,6 +173,4 @@ export class ProjectViewIssues extends BaseIssuesStore implements IProjectViewIs
return await this.fetchIssues(workspaceSlug, projectId, viewId, loadType, this.paginationOptions, true);
};
archiveBulkIssues = this.bulkArchiveIssues;
quickAddIssue = this.issueQuickAdd;
}
@@ -164,7 +164,4 @@ export class ProjectIssues extends BaseIssuesStore implements IProjectIssues {
if (!this.paginationOptions) return;
return await this.fetchIssues(workspaceSlug, projectId, loadType, this.paginationOptions, true);
};
archiveBulkIssues = this.bulkArchiveIssues;
quickAddIssue = this.issueQuickAdd;
}
@@ -43,8 +43,8 @@ export interface IWorkspaceIssues extends IBaseIssuesStore {
removeBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
archiveBulkIssues: (workspaceSlug: string, projectId: string, issueIds: string[]) => Promise<void>;
bulkUpdateProperties: (workspaceSlug: string, projectId: string, data: TBulkOperationsPayload) => Promise<void>;
quickAddIssue: (workspaceSlug: string, projectId: string, data: TIssue, id?: string) => Promise<TIssue | undefined>;
quickAddIssue: undefined;
clear(): void;
}
@@ -167,6 +167,9 @@ export class WorkspaceIssues extends BaseIssuesStore implements IWorkspaceIssues
return await this.fetchIssues(workspaceSlug, viewId, loadType, this.paginationOptions, true);
};
archiveBulkIssues = this.bulkArchiveIssues;
quickAddIssue = undefined;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
override quickAddIssue(workspaceSlug: string, projectId: string, data: TIssue, id?: string) {
console.warn("cannot quick Add to workspace issues");
return Promise.resolve(undefined);
}
}