mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
Merge branch 'preview' of gurusainath:makeplane/plane into revamp-estimates
This commit is contained in:
commit
a3c9d5639e
@ -19,14 +19,14 @@ const InstanceAIPage = observer(() => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader title="Artificial Intelligence - God Mode" />
|
<PageHeader title="Artificial Intelligence - God Mode" />
|
||||||
<div className="relative container mx-auto w-full h-full p-8 py-4 space-y-6 flex flex-col">
|
<div className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col">
|
||||||
<div className="border-b border-custom-border-100 pb-3 space-y-1 flex-shrink-0">
|
<div className="border-b border-custom-border-100 mx-4 py-4 space-y-1 flex-shrink-0">
|
||||||
<div className="text-xl font-medium text-custom-text-100">AI features for all your workspaces</div>
|
<div className="text-xl font-medium text-custom-text-100">AI features for all your workspaces</div>
|
||||||
<div className="text-sm font-normal text-custom-text-300">
|
<div className="text-sm font-normal text-custom-text-300">
|
||||||
Configure your AI API credentials so Plane AI features are turned on for all your workspaces.
|
Configure your AI API credentials so Plane AI features are turned on for all your workspaces.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-grow overflow-hidden overflow-y-auto">
|
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-4">
|
||||||
{formattedConfig ? (
|
{formattedConfig ? (
|
||||||
<InstanceAIForm config={formattedConfig} />
|
<InstanceAIForm config={formattedConfig} />
|
||||||
) : (
|
) : (
|
||||||
|
@ -64,8 +64,8 @@ const InstanceGithubAuthenticationPage = observer(() => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader title="Authentication - God Mode" />
|
<PageHeader title="Authentication - God Mode" />
|
||||||
<div className="relative container mx-auto w-full h-full p-8 py-4 space-y-6 flex flex-col">
|
<div className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col">
|
||||||
<div className="border-b border-custom-border-100 pb-3 space-y-1 flex-shrink-0">
|
<div className="border-b border-custom-border-100 mx-4 py-4 space-y-1 flex-shrink-0">
|
||||||
<AuthenticationMethodCard
|
<AuthenticationMethodCard
|
||||||
name="Github"
|
name="Github"
|
||||||
description="Allow members to login or sign up to plane with their Github accounts."
|
description="Allow members to login or sign up to plane with their Github accounts."
|
||||||
@ -93,7 +93,7 @@ const InstanceGithubAuthenticationPage = observer(() => {
|
|||||||
withBorder={false}
|
withBorder={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-grow overflow-hidden overflow-y-auto">
|
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md p-4">
|
||||||
{formattedConfig ? (
|
{formattedConfig ? (
|
||||||
<InstanceGithubConfigForm config={formattedConfig} />
|
<InstanceGithubConfigForm config={formattedConfig} />
|
||||||
) : (
|
) : (
|
||||||
|
@ -58,8 +58,8 @@ const InstanceGoogleAuthenticationPage = observer(() => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader title="Authentication - God Mode" />
|
<PageHeader title="Authentication - God Mode" />
|
||||||
<div className="relative container mx-auto w-full h-full p-8 py-4 space-y-6 flex flex-col">
|
<div className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col">
|
||||||
<div className="border-b border-custom-border-100 pb-3 space-y-1 flex-shrink-0">
|
<div className="border-b border-custom-border-100 mx-4 py-4 space-y-1 flex-shrink-0">
|
||||||
<AuthenticationMethodCard
|
<AuthenticationMethodCard
|
||||||
name="Google"
|
name="Google"
|
||||||
description="Allow members to login or sign up to plane with their Google
|
description="Allow members to login or sign up to plane with their Google
|
||||||
@ -81,7 +81,7 @@ const InstanceGoogleAuthenticationPage = observer(() => {
|
|||||||
withBorder={false}
|
withBorder={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-grow overflow-hidden overflow-y-auto">
|
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md p-4">
|
||||||
{formattedConfig ? (
|
{formattedConfig ? (
|
||||||
<InstanceGoogleConfigForm config={formattedConfig} />
|
<InstanceGoogleConfigForm config={formattedConfig} />
|
||||||
) : (
|
) : (
|
||||||
|
@ -119,14 +119,14 @@ const InstanceAuthenticationPage = observer(() => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader title="Authentication - God Mode" />
|
<PageHeader title="Authentication - God Mode" />
|
||||||
<div className="relative container mx-auto w-full h-full p-8 py-4 space-y-6 flex flex-col">
|
<div className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col">
|
||||||
<div className="border-b border-custom-border-100 pb-3 space-y-1 flex-shrink-0">
|
<div className="border-b border-custom-border-100 mx-4 py-4 space-y-1 flex-shrink-0">
|
||||||
<div className="text-xl font-medium text-custom-text-100">Manage authentication for your instance</div>
|
<div className="text-xl font-medium text-custom-text-100">Manage authentication for your instance</div>
|
||||||
<div className="text-sm font-normal text-custom-text-300">
|
<div className="text-sm font-normal text-custom-text-300">
|
||||||
Configure authentication modes for your team and restrict sign ups to be invite only.
|
Configure authentication modes for your team and restrict sign ups to be invite only.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-grow overflow-hidden overflow-y-auto">
|
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-4">
|
||||||
{formattedConfig ? (
|
{formattedConfig ? (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div className="text-lg font-medium">Authentication modes</div>
|
<div className="text-lg font-medium">Authentication modes</div>
|
||||||
|
@ -19,8 +19,8 @@ const InstanceEmailPage = observer(() => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader title="Email - God Mode" />
|
<PageHeader title="Email - God Mode" />
|
||||||
<div className="relative container mx-auto w-full h-full p-8 py-4 space-y-6 flex flex-col">
|
<div className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col">
|
||||||
<div className="border-b border-custom-border-100 pb-3 space-y-1 flex-shrink-0">
|
<div className="border-b border-custom-border-100 mx-4 py-4 space-y-1 flex-shrink-0">
|
||||||
<div className="text-xl font-medium text-custom-text-100">Secure emails from your own instance</div>
|
<div className="text-xl font-medium text-custom-text-100">Secure emails from your own instance</div>
|
||||||
<div className="text-sm font-normal text-custom-text-300">
|
<div className="text-sm font-normal text-custom-text-300">
|
||||||
Plane can send useful emails to you and your users from your own instance without talking to the Internet.
|
Plane can send useful emails to you and your users from your own instance without talking to the Internet.
|
||||||
@ -30,7 +30,7 @@ const InstanceEmailPage = observer(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-grow overflow-hidden overflow-y-auto">
|
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-4">
|
||||||
{formattedConfig ? (
|
{formattedConfig ? (
|
||||||
<InstanceEmailForm config={formattedConfig} />
|
<InstanceEmailForm config={formattedConfig} />
|
||||||
) : (
|
) : (
|
||||||
|
@ -51,7 +51,7 @@ export const SendTestEmailModal: FC<Props> = (props) => {
|
|||||||
setSendEmailStep(ESendEmailSteps.SUCCESS);
|
setSendEmailStep(ESendEmailSteps.SUCCESS);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setError(error?.message || "Failed to send email");
|
setError(error?.error || "Failed to send email");
|
||||||
setSendEmailStep(ESendEmailSteps.FAILED);
|
setSendEmailStep(ESendEmailSteps.FAILED);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
@ -10,15 +10,15 @@ function GeneralPage() {
|
|||||||
console.log("instance", instance);
|
console.log("instance", instance);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="relative container mx-auto w-full h-full p-8 py-4 space-y-6 flex flex-col">
|
<div className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col">
|
||||||
<div className="border-b border-custom-border-100 pb-3 space-y-1 flex-shrink-0">
|
<div className="border-b border-custom-border-100 mx-4 py-4 space-y-1 flex-shrink-0">
|
||||||
<div className="text-xl font-medium text-custom-text-100">General settings</div>
|
<div className="text-xl font-medium text-custom-text-100">General settings</div>
|
||||||
<div className="text-sm font-normal text-custom-text-300">
|
<div className="text-sm font-normal text-custom-text-300">
|
||||||
Change the name of your instance and instance admin e-mail addresses. Enable or disable telemetry in your
|
Change the name of your instance and instance admin e-mail addresses. Enable or disable telemetry in your
|
||||||
instance.
|
instance.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-grow overflow-hidden overflow-y-auto">
|
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-4">
|
||||||
{instance && instanceAdmins && (
|
{instance && instanceAdmins && (
|
||||||
<GeneralConfigurationForm instance={instance} instanceAdmins={instanceAdmins} />
|
<GeneralConfigurationForm instance={instance} instanceAdmins={instanceAdmins} />
|
||||||
)}
|
)}
|
||||||
|
@ -332,42 +332,90 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* scrollbar style */
|
/* scrollbar style */
|
||||||
::-webkit-scrollbar {
|
@-moz-document url-prefix() {
|
||||||
display: none;
|
* {
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.vertical-scrollbar,
|
||||||
|
.horizontal-scrollbar {
|
||||||
|
scrollbar-width: initial;
|
||||||
|
scrollbar-color: rgba(96, 100, 108, 0.1) transparent;
|
||||||
|
}
|
||||||
|
.vertical-scrollbar:hover,
|
||||||
|
.horizontal-scrollbar:hover {
|
||||||
|
scrollbar-color: rgba(96, 100, 108, 0.25) transparent;
|
||||||
|
}
|
||||||
|
.vertical-scrollbar:active,
|
||||||
|
.horizontal-scrollbar:active {
|
||||||
|
scrollbar-color: rgba(96, 100, 108, 0.7) transparent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.horizontal-scroll-enable {
|
.vertical-scrollbar {
|
||||||
overflow-x: scroll;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
.horizontal-scrollbar {
|
||||||
.horizontal-scroll-enable::-webkit-scrollbar {
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
.vertical-scrollbar::-webkit-scrollbar,
|
||||||
|
.horizontal-scrollbar::-webkit-scrollbar {
|
||||||
display: block;
|
display: block;
|
||||||
height: 7px;
|
}
|
||||||
width: 0;
|
.vertical-scrollbar::-webkit-scrollbar-track,
|
||||||
|
.horizontal-scrollbar::-webkit-scrollbar-track {
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
.vertical-scrollbar::-webkit-scrollbar-thumb,
|
||||||
|
.horizontal-scrollbar::-webkit-scrollbar-thumb {
|
||||||
|
background-clip: padding-box;
|
||||||
|
background-color: rgba(96, 100, 108, 0.1);
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
.vertical-scrollbar:hover::-webkit-scrollbar-thumb,
|
||||||
|
.horizontal-scrollbar:hover::-webkit-scrollbar-thumb {
|
||||||
|
background-color: rgba(96, 100, 108, 0.25);
|
||||||
|
}
|
||||||
|
.vertical-scrollbar::-webkit-scrollbar-thumb:hover,
|
||||||
|
.horizontal-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: rgba(96, 100, 108, 0.5);
|
||||||
|
}
|
||||||
|
.vertical-scrollbar::-webkit-scrollbar-thumb:active,
|
||||||
|
.horizontal-scrollbar::-webkit-scrollbar-thumb:active {
|
||||||
|
background-color: rgba(96, 100, 108, 0.7);
|
||||||
|
}
|
||||||
|
.vertical-scrollbar::-webkit-scrollbar-corner,
|
||||||
|
.horizontal-scrollbar::-webkit-scrollbar-corner {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
.vertical-scrollbar-margin-top-md::-webkit-scrollbar-track {
|
||||||
|
margin-top: 44px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.horizontal-scroll-enable::-webkit-scrollbar-track {
|
/* scrollbar sm size */
|
||||||
height: 7px;
|
.scrollbar-sm::-webkit-scrollbar {
|
||||||
background-color: rgba(var(--color-background-100));
|
height: 12px;
|
||||||
|
width: 12px;
|
||||||
}
|
}
|
||||||
|
.scrollbar-sm::-webkit-scrollbar-thumb {
|
||||||
.horizontal-scroll-enable::-webkit-scrollbar-thumb {
|
border: 3px solid rgba(0, 0, 0, 0);
|
||||||
border-radius: 5px;
|
|
||||||
background-color: rgba(var(--color-scrollbar));
|
|
||||||
}
|
}
|
||||||
|
/* scrollbar md size */
|
||||||
.vertical-scroll-enable::-webkit-scrollbar {
|
.scrollbar-md::-webkit-scrollbar {
|
||||||
display: block;
|
height: 14px;
|
||||||
width: 5px;
|
width: 14px;
|
||||||
}
|
}
|
||||||
|
.scrollbar-md::-webkit-scrollbar-thumb {
|
||||||
.vertical-scroll-enable::-webkit-scrollbar-track {
|
border: 3px solid rgba(0, 0, 0, 0);
|
||||||
width: 5px;
|
|
||||||
}
|
}
|
||||||
|
/* scrollbar lg size */
|
||||||
|
|
||||||
.vertical-scroll-enable::-webkit-scrollbar-thumb {
|
.scrollbar-lg::-webkit-scrollbar {
|
||||||
border-radius: 5px;
|
height: 16px;
|
||||||
background-color: rgba(var(--color-background-90));
|
width: 16px;
|
||||||
|
}
|
||||||
|
.scrollbar-lg::-webkit-scrollbar-thumb {
|
||||||
|
border: 4px solid rgba(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
/* end scrollbar style */
|
/* end scrollbar style */
|
||||||
|
|
||||||
|
@ -19,14 +19,14 @@ const InstanceImagePage = observer(() => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageHeader title="Image - God Mode" />
|
<PageHeader title="Image - God Mode" />
|
||||||
<div className="relative container mx-auto w-full h-full p-8 py-4 space-y-6 flex flex-col">
|
<div className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col">
|
||||||
<div className="border-b border-custom-border-100 pb-3 space-y-1 flex-shrink-0">
|
<div className="border-b border-custom-border-100 mx-4 py-4 space-y-1 flex-shrink-0">
|
||||||
<div className="text-xl font-medium text-custom-text-100">Third-party image libraries</div>
|
<div className="text-xl font-medium text-custom-text-100">Third-party image libraries</div>
|
||||||
<div className="text-sm font-normal text-custom-text-300">
|
<div className="text-sm font-normal text-custom-text-300">
|
||||||
Let your users search and choose images from third-party libraries
|
Let your users search and choose images from third-party libraries
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-grow overflow-hidden overflow-y-auto">
|
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-4">
|
||||||
{formattedConfig ? (
|
{formattedConfig ? (
|
||||||
<InstanceImageConfigForm config={formattedConfig} />
|
<InstanceImageConfigForm config={formattedConfig} />
|
||||||
) : (
|
) : (
|
||||||
|
@ -38,7 +38,7 @@ export const HelpSection: FC = observer(() => {
|
|||||||
// refs
|
// refs
|
||||||
const helpOptionsRef = useRef<HTMLDivElement | null>(null);
|
const helpOptionsRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const redirectionLink = encodeURI(WEB_BASE_URL + "/create-workspace");
|
const redirectionLink = encodeURI(WEB_BASE_URL + "/");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -56,7 +56,7 @@ export const SidebarMenu = observer(() => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full w-full flex-col gap-2.5 overflow-y-auto px-4 py-4">
|
<div className="flex h-full w-full flex-col gap-2.5 overflow-y-scroll vertical-scrollbar scrollbar-sm px-4 py-4">
|
||||||
{INSTANCE_ADMIN_LINKS.map((item, index) => {
|
{INSTANCE_ADMIN_LINKS.map((item, index) => {
|
||||||
const isActive = item.href === pathName || pathName.includes(item.href);
|
const isActive = item.href === pathName || pathName.includes(item.href);
|
||||||
return (
|
return (
|
||||||
|
@ -158,6 +158,7 @@ export const InstanceSetupForm: FC = (props) => {
|
|||||||
onError={() => setIsSubmitting(false)}
|
onError={() => setIsSubmitting(false)}
|
||||||
>
|
>
|
||||||
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />
|
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />
|
||||||
|
<input type="hidden" name="is_telemetry_enabled" value={formData.is_telemetry_enabled ? "True" : "False"} />
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row items-center gap-4">
|
<div className="flex flex-col sm:flex-row items-center gap-4">
|
||||||
<div className="w-full space-y-1">
|
<div className="w-full space-y-1">
|
||||||
@ -319,8 +320,6 @@ export const InstanceSetupForm: FC = (props) => {
|
|||||||
<div>
|
<div>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="is_telemetry_enabled"
|
id="is_telemetry_enabled"
|
||||||
name="is_telemetry_enabled"
|
|
||||||
value={formData.is_telemetry_enabled ? "True" : "False"}
|
|
||||||
onChange={() => handleFormChange("is_telemetry_enabled", !formData.is_telemetry_enabled)}
|
onChange={() => handleFormChange("is_telemetry_enabled", !formData.is_telemetry_enabled)}
|
||||||
checked={formData.is_telemetry_enabled}
|
checked={formData.is_telemetry_enabled}
|
||||||
/>
|
/>
|
||||||
|
@ -7,9 +7,9 @@ import { useTheme as nextUseTheme } from "next-themes";
|
|||||||
// ui
|
// ui
|
||||||
import { Button, getButtonStyling } from "@plane/ui";
|
import { Button, getButtonStyling } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { resolveGeneralTheme } from "helpers/common.helper";
|
import { WEB_BASE_URL, resolveGeneralTheme } from "helpers/common.helper";
|
||||||
// hooks
|
// hooks
|
||||||
import { useInstance, useTheme } from "@/hooks/store";
|
import { useTheme } from "@/hooks/store";
|
||||||
// icons
|
// icons
|
||||||
import TakeoffIconLight from "/public/logos/takeoff-icon-light.svg";
|
import TakeoffIconLight from "/public/logos/takeoff-icon-light.svg";
|
||||||
import TakeoffIconDark from "/public/logos/takeoff-icon-dark.svg";
|
import TakeoffIconDark from "/public/logos/takeoff-icon-dark.svg";
|
||||||
@ -17,11 +17,10 @@ import TakeoffIconDark from "/public/logos/takeoff-icon-dark.svg";
|
|||||||
export const NewUserPopup: React.FC = observer(() => {
|
export const NewUserPopup: React.FC = observer(() => {
|
||||||
// hooks
|
// hooks
|
||||||
const { isNewUserPopup, toggleNewUserPopup } = useTheme();
|
const { isNewUserPopup, toggleNewUserPopup } = useTheme();
|
||||||
const { config } = useInstance();
|
|
||||||
// theme
|
// theme
|
||||||
const { resolvedTheme } = nextUseTheme();
|
const { resolvedTheme } = nextUseTheme();
|
||||||
|
|
||||||
const redirectionLink = `${config?.app_base_url ? `${config?.app_base_url}/create-workspace` : `/god-mode/`}`;
|
const redirectionLink = encodeURI(WEB_BASE_URL + "/create-workspace");
|
||||||
|
|
||||||
if (!isNewUserPopup) return <></>;
|
if (!isNewUserPopup) return <></>;
|
||||||
return (
|
return (
|
||||||
|
@ -17,6 +17,7 @@ AUTHENTICATION_ERROR_CODES = {
|
|||||||
"INVALID_EMAIL_SIGN_UP": 5045,
|
"INVALID_EMAIL_SIGN_UP": 5045,
|
||||||
"INVALID_EMAIL_MAGIC_SIGN_UP": 5050,
|
"INVALID_EMAIL_MAGIC_SIGN_UP": 5050,
|
||||||
"MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED": 5055,
|
"MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED": 5055,
|
||||||
|
"EMAIL_PASSWORD_AUTHENTICATION_DISABLED": 5056,
|
||||||
# Sign In
|
# Sign In
|
||||||
"USER_DOES_NOT_EXIST": 5060,
|
"USER_DOES_NOT_EXIST": 5060,
|
||||||
"AUTHENTICATION_FAILED_SIGN_IN": 5065,
|
"AUTHENTICATION_FAILED_SIGN_IN": 5065,
|
||||||
|
@ -41,8 +41,10 @@ class EmailProvider(CredentialAdapter):
|
|||||||
|
|
||||||
if ENABLE_EMAIL_PASSWORD == "0":
|
if ENABLE_EMAIL_PASSWORD == "0":
|
||||||
raise AuthenticationException(
|
raise AuthenticationException(
|
||||||
error_code=AUTHENTICATION_ERROR_CODES["ENABLE_EMAIL_PASSWORD"],
|
error_code=AUTHENTICATION_ERROR_CODES[
|
||||||
error_message="ENABLE_EMAIL_PASSWORD",
|
"EMAIL_PASSWORD_AUTHENTICATION_DISABLED"
|
||||||
|
],
|
||||||
|
error_message="EMAIL_PASSWORD_AUTHENTICATION_DISABLED",
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_user_data(self):
|
def set_user_data(self):
|
||||||
|
@ -148,7 +148,7 @@ class InstanceEndpoint(BaseAPIView):
|
|||||||
data["app_base_url"] = settings.APP_BASE_URL
|
data["app_base_url"] = settings.APP_BASE_URL
|
||||||
|
|
||||||
instance_data = serializer.data
|
instance_data = serializer.data
|
||||||
instance_data["workspaces_exist"] = Workspace.objects.count() > 1
|
instance_data["workspaces_exist"] = Workspace.objects.count() >= 1
|
||||||
|
|
||||||
response_data = {"config": data, "instance": instance_data}
|
response_data = {"config": data, "instance": instance_data}
|
||||||
return Response(response_data, status=status.HTTP_200_OK)
|
return Response(response_data, status=status.HTTP_200_OK)
|
||||||
|
@ -68,7 +68,7 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
|
|||||||
setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id, nestingLevel: nestingLevel });
|
setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id, nestingLevel: nestingLevel });
|
||||||
|
|
||||||
const issue = issuesMap[issueId];
|
const issue = issuesMap[issueId];
|
||||||
const subIssuesCount = issue.sub_issues_count;
|
const subIssuesCount = issue?.sub_issues_count ?? 0;
|
||||||
|
|
||||||
const { isMobile } = usePlatformOS();
|
const { isMobile } = usePlatformOS();
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
const currentLayout = `${activeLayout} layout`;
|
const currentLayout = `${activeLayout} layout`;
|
||||||
// derived values
|
// derived values
|
||||||
const stateDetails = getStateById(issue.state_id);
|
const stateDetails = getStateById(issue.state_id);
|
||||||
const subIssueCount = issue.sub_issues_count;
|
const subIssueCount = issue?.sub_issues_count ?? 0;
|
||||||
|
|
||||||
const issueOperations = useMemo(
|
const issueOperations = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
@ -19,7 +19,7 @@ export const SpreadsheetSubIssueColumn: React.FC<Props> = observer((props: Props
|
|||||||
// hooks
|
// hooks
|
||||||
const { workspaceSlug } = useAppRouter();
|
const { workspaceSlug } = useAppRouter();
|
||||||
// derived values
|
// derived values
|
||||||
const subIssueCount = issue.sub_issues_count;
|
const subIssueCount = issue?.sub_issues_count ?? 0;
|
||||||
|
|
||||||
const redirectToIssueDetail = () => {
|
const redirectToIssueDetail = () => {
|
||||||
router.push({
|
router.push({
|
||||||
|
@ -203,7 +203,7 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const disableUserActions = !canEditProperties(issueDetail.project_id);
|
const disableUserActions = !canEditProperties(issueDetail.project_id);
|
||||||
const subIssuesCount = issueDetail.sub_issues_count;
|
const subIssuesCount = issueDetail?.sub_issues_count ?? 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -61,7 +61,7 @@ export const IssueListItem: React.FC<ISubIssues> = observer((props) => {
|
|||||||
undefined;
|
undefined;
|
||||||
|
|
||||||
const subIssueHelpers = subIssueHelpersByIssueId(parentIssueId);
|
const subIssueHelpers = subIssueHelpersByIssueId(parentIssueId);
|
||||||
const subIssueCount = issue?.sub_issues_count || 0;
|
const subIssueCount = issue?.sub_issues_count ?? 0;
|
||||||
|
|
||||||
const handleIssuePeekOverview = (issue: TIssue) =>
|
const handleIssuePeekOverview = (issue: TIssue) =>
|
||||||
workspaceSlug &&
|
workspaceSlug &&
|
||||||
|
@ -59,9 +59,8 @@ const calculateShades = (hexValue: string): TShades => {
|
|||||||
return shades as TShades;
|
return shades as TShades;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const applyTheme = (palette: string, isDarkPalette: boolean) => {
|
export const applyTheme = (palette: string, isDarkPalette: boolean, dom: HTMLElement | null) => {
|
||||||
if (!palette) return;
|
if (!palette) return;
|
||||||
const dom = document?.querySelector<HTMLElement>("[data-theme='custom']");
|
|
||||||
// palette: [bg, text, primary, sidebarBg, sidebarText]
|
// palette: [bg, text, primary, sidebarBg, sidebarText]
|
||||||
const values: string[] = palette.split(",");
|
const values: string[] = palette.split(",");
|
||||||
values.push(isDarkPalette ? "dark" : "light");
|
values.push(isDarkPalette ? "dark" : "light");
|
||||||
|
@ -22,7 +22,7 @@ const StoreWrapper: FC<TStoreWrapper> = observer((props) => {
|
|||||||
const { sidebarCollapsed, toggleSidebar } = useAppTheme();
|
const { sidebarCollapsed, toggleSidebar } = useAppTheme();
|
||||||
const { data: userProfile } = useUserProfile();
|
const { data: userProfile } = useUserProfile();
|
||||||
// states
|
// states
|
||||||
const [dom, setDom] = useState<undefined | HTMLElement>();
|
const [dom, setDom] = useState<HTMLElement | null>(null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sidebar collapsed fetching from local storage
|
* Sidebar collapsed fetching from local storage
|
||||||
@ -38,19 +38,40 @@ const StoreWrapper: FC<TStoreWrapper> = observer((props) => {
|
|||||||
* Setting up the theme of the user by fetching it from local storage
|
* Setting up the theme of the user by fetching it from local storage
|
||||||
*/
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!userProfile?.theme?.theme) return;
|
|
||||||
if (window) setDom(() => window.document?.querySelector<HTMLElement>("[data-theme='custom']") || undefined);
|
|
||||||
|
|
||||||
setTheme(userProfile?.theme?.theme || "system");
|
setTheme(userProfile?.theme?.theme || "system");
|
||||||
if (userProfile?.theme?.theme === "custom" && userProfile?.theme?.palette && dom)
|
if (!userProfile?.theme?.theme) return;
|
||||||
|
|
||||||
|
if (userProfile?.theme?.theme === "custom" && userProfile?.theme?.palette) {
|
||||||
applyTheme(
|
applyTheme(
|
||||||
userProfile?.theme?.palette !== ",,,,"
|
userProfile?.theme?.palette !== ",,,,"
|
||||||
? userProfile?.theme?.palette
|
? userProfile?.theme?.palette
|
||||||
: "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
|
: "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
|
||||||
false
|
false,
|
||||||
|
dom
|
||||||
);
|
);
|
||||||
else unsetCustomCssVariables();
|
} else unsetCustomCssVariables();
|
||||||
}, [userProfile, userProfile?.theme?.theme, userProfile?.theme?.palette, setTheme, dom]);
|
}, [userProfile, userProfile?.theme, userProfile?.theme?.palette, setTheme, dom]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (dom) return;
|
||||||
|
|
||||||
|
const observer = new MutationObserver((mutationsList, observer) => {
|
||||||
|
for (const mutation of mutationsList) {
|
||||||
|
if (mutation.type === "childList") {
|
||||||
|
const customThemeElement = window.document?.querySelector<HTMLElement>("[data-theme='custom']");
|
||||||
|
if (customThemeElement) {
|
||||||
|
setDom(customThemeElement);
|
||||||
|
observer.disconnect();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, [dom]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!router.query) return;
|
if (!router.query) return;
|
||||||
|
@ -69,6 +69,10 @@ const nextConfig = {
|
|||||||
const ADMIN_BASE_URL = process.env.NEXT_PUBLIC_ADMIN_BASE_URL || "";
|
const ADMIN_BASE_URL = process.env.NEXT_PUBLIC_ADMIN_BASE_URL || "";
|
||||||
const ADMIN_BASE_PATH = process.env.NEXT_PUBLIC_ADMIN_BASE_PATH || "";
|
const ADMIN_BASE_PATH = process.env.NEXT_PUBLIC_ADMIN_BASE_PATH || "";
|
||||||
const GOD_MODE_BASE_URL = ADMIN_BASE_URL + ADMIN_BASE_PATH;
|
const GOD_MODE_BASE_URL = ADMIN_BASE_URL + ADMIN_BASE_PATH;
|
||||||
|
rewrites.push({
|
||||||
|
source: "/god-mode",
|
||||||
|
destination: `${GOD_MODE_BASE_URL}/`,
|
||||||
|
})
|
||||||
rewrites.push({
|
rewrites.push({
|
||||||
source: "/god-mode/:path*",
|
source: "/god-mode/:path*",
|
||||||
destination: `${GOD_MODE_BASE_URL}/:path*`,
|
destination: `${GOD_MODE_BASE_URL}/:path*`,
|
||||||
|
@ -293,24 +293,26 @@ export class CycleIssues extends IssueHelperStore implements ICycleIssues {
|
|||||||
|
|
||||||
const response = await this.createIssue(workspaceSlug, projectId, data, cycleId);
|
const response = await this.createIssue(workspaceSlug, projectId, data, cycleId);
|
||||||
|
|
||||||
if (data.module_ids && data.module_ids.length > 0)
|
const quickAddIssueIndex = this.issues[cycleId].findIndex((_issueId) => _issueId === data.id);
|
||||||
|
if (quickAddIssueIndex >= 0) {
|
||||||
|
runInAction(() => {
|
||||||
|
this.issues[cycleId].splice(quickAddIssueIndex, 1);
|
||||||
|
this.rootIssueStore.issues.removeIssue(data.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.module_ids && data.module_ids.length > 0) {
|
||||||
await this.rootStore.moduleIssues.changeModulesInIssue(
|
await this.rootStore.moduleIssues.changeModulesInIssue(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
response.id,
|
response.id,
|
||||||
data.module_ids,
|
data.module_ids,
|
||||||
[]
|
[]
|
||||||
);
|
)
|
||||||
|
}
|
||||||
|
|
||||||
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);
|
this.rootIssueStore.rootStore.cycle.fetchCycleDetails(workspaceSlug, projectId, cycleId);
|
||||||
|
|
||||||
const quickAddIssueIndex = this.issues[cycleId].findIndex((_issueId) => _issueId === data.id);
|
|
||||||
if (quickAddIssueIndex >= 0)
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[cycleId].splice(quickAddIssueIndex, 1);
|
|
||||||
this.rootIssueStore.issues.removeIssue(data.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (cycleId) this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
if (cycleId) this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
||||||
|
@ -111,8 +111,8 @@ export class IssueStore implements IIssueStore {
|
|||||||
|
|
||||||
// store handlers from issue detail
|
// store handlers from issue detail
|
||||||
// parent
|
// parent
|
||||||
if (issue && issue?.parent && issue?.parent?.id) {
|
if (issue && issue?.parent && issue?.parent?.id && issue?.parent?.project_id) {
|
||||||
const parentIssue = await this.issueService.retrieve(workspaceSlug, projectId, issue?.parent?.id);
|
const parentIssue = await this.issueService.retrieve(workspaceSlug, issue.parent.project_id, issue?.parent?.id);
|
||||||
this.rootIssueDetailStore.rootIssueStore.issues.addIssue([parentIssue]);
|
this.rootIssueDetailStore.rootIssueStore.issues.addIssue([parentIssue]);
|
||||||
}
|
}
|
||||||
// assignees
|
// assignees
|
||||||
|
@ -294,17 +294,19 @@ export class ModuleIssues extends IssueHelperStore implements IModuleIssues {
|
|||||||
|
|
||||||
const response = await this.createIssue(workspaceSlug, projectId, data, moduleId);
|
const response = await this.createIssue(workspaceSlug, projectId, data, moduleId);
|
||||||
|
|
||||||
if (data.cycle_id && data.cycle_id !== "")
|
|
||||||
await this.rootStore.cycleIssues.addIssueToCycle(workspaceSlug, projectId, data.cycle_id, [response.id]);
|
|
||||||
|
|
||||||
this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
|
||||||
|
|
||||||
const quickAddIssueIndex = this.issues[moduleId].findIndex((_issueId) => _issueId === data.id);
|
const quickAddIssueIndex = this.issues[moduleId].findIndex((_issueId) => _issueId === data.id);
|
||||||
if (quickAddIssueIndex >= 0)
|
if (quickAddIssueIndex >= 0) {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.issues[moduleId].splice(quickAddIssueIndex, 1);
|
this.issues[moduleId].splice(quickAddIssueIndex, 1);
|
||||||
this.rootIssueStore.issues.removeIssue(data.id);
|
this.rootIssueStore.issues.removeIssue(data.id);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.cycle_id && data.cycle_id !== "") {
|
||||||
|
await this.rootStore.cycleIssues.addCycleToIssue(workspaceSlug, projectId, data.cycle_id, response.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.rootIssueStore.rootStore.module.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -239,24 +239,27 @@ export class ProjectViewIssues extends IssueHelperStore implements IProjectViewI
|
|||||||
|
|
||||||
const response = await this.createIssue(workspaceSlug, projectId, data, viewId);
|
const response = await this.createIssue(workspaceSlug, projectId, data, viewId);
|
||||||
|
|
||||||
if (data.cycle_id && data.cycle_id !== "")
|
const quickAddIssueIndex = this.issues[viewId].findIndex((_issueId) => _issueId === data.id);
|
||||||
await this.rootStore.cycleIssues.addIssueToCycle(workspaceSlug, projectId, data.cycle_id, [response.id]);
|
if (quickAddIssueIndex >= 0) {
|
||||||
|
runInAction(() => {
|
||||||
|
this.issues[viewId].splice(quickAddIssueIndex, 1);
|
||||||
|
this.rootIssueStore.issues.removeIssue(data.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (data.module_ids && data.module_ids.length > 0)
|
if (data.cycle_id && data.cycle_id !== "") {
|
||||||
|
await this.rootStore.cycleIssues.addCycleToIssue(workspaceSlug, projectId, data.cycle_id, response.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.module_ids && data.module_ids.length > 0) {
|
||||||
await this.rootStore.moduleIssues.changeModulesInIssue(
|
await this.rootStore.moduleIssues.changeModulesInIssue(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
response.id,
|
response.id,
|
||||||
data.module_ids,
|
data.module_ids,
|
||||||
[]
|
[]
|
||||||
);
|
)
|
||||||
|
}
|
||||||
const quickAddIssueIndex = this.issues[viewId].findIndex((_issueId) => _issueId === data.id);
|
|
||||||
if (quickAddIssueIndex >= 0)
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[viewId].splice(quickAddIssueIndex, 1);
|
|
||||||
this.rootIssueStore.issues.removeIssue(data.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -243,24 +243,29 @@ export class ProjectIssues extends IssueHelperStore implements IProjectIssues {
|
|||||||
|
|
||||||
const response = await this.createIssue(workspaceSlug, projectId, data);
|
const response = await this.createIssue(workspaceSlug, projectId, data);
|
||||||
|
|
||||||
if (data.cycle_id && data.cycle_id !== "")
|
const quickAddIssueIndex = this.issues[projectId].findIndex((_issueId) => _issueId === data.id);
|
||||||
await this.rootStore.cycleIssues.addIssueToCycle(workspaceSlug, projectId, data.cycle_id, [response.id]);
|
|
||||||
|
|
||||||
if (data.module_ids && data.module_ids.length > 0)
|
if (quickAddIssueIndex >= 0) {
|
||||||
|
runInAction(() => {
|
||||||
|
this.issues[projectId].splice(quickAddIssueIndex, 1);
|
||||||
|
this.rootStore.issues.removeIssue(data.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: error handling needs to be improved for rare cases
|
||||||
|
if (data.cycle_id && data.cycle_id !== "") {
|
||||||
|
await this.rootStore.cycleIssues.addCycleToIssue(workspaceSlug, projectId, data.cycle_id, response.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.module_ids && data.module_ids.length > 0) {
|
||||||
await this.rootStore.moduleIssues.changeModulesInIssue(
|
await this.rootStore.moduleIssues.changeModulesInIssue(
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
response.id,
|
response.id,
|
||||||
data.module_ids,
|
data.module_ids,
|
||||||
[]
|
[]
|
||||||
);
|
)
|
||||||
|
}
|
||||||
const quickAddIssueIndex = this.issues[projectId].findIndex((_issueId) => _issueId === data.id);
|
|
||||||
if (quickAddIssueIndex >= 0)
|
|
||||||
runInAction(() => {
|
|
||||||
this.issues[projectId].splice(quickAddIssueIndex, 1);
|
|
||||||
this.rootStore.issues.removeIssue(data.id);
|
|
||||||
});
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.fetchIssues(workspaceSlug, projectId, "mutation");
|
this.fetchIssues(workspaceSlug, projectId, "mutation");
|
||||||
|
Loading…
Reference in New Issue
Block a user