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 (
|
||||
<>
|
||||
<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="border-b border-custom-border-100 pb-3 space-y-1 flex-shrink-0">
|
||||
<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 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-sm font-normal text-custom-text-300">
|
||||
Configure your AI API credentials so Plane AI features are turned on for all your workspaces.
|
||||
</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 ? (
|
||||
<InstanceAIForm config={formattedConfig} />
|
||||
) : (
|
||||
|
@ -64,8 +64,8 @@ const InstanceGithubAuthenticationPage = observer(() => {
|
||||
return (
|
||||
<>
|
||||
<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="border-b border-custom-border-100 pb-3 space-y-1 flex-shrink-0">
|
||||
<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 mx-4 py-4 space-y-1 flex-shrink-0">
|
||||
<AuthenticationMethodCard
|
||||
name="Github"
|
||||
description="Allow members to login or sign up to plane with their Github accounts."
|
||||
@ -93,7 +93,7 @@ const InstanceGithubAuthenticationPage = observer(() => {
|
||||
withBorder={false}
|
||||
/>
|
||||
</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 ? (
|
||||
<InstanceGithubConfigForm config={formattedConfig} />
|
||||
) : (
|
||||
|
@ -58,8 +58,8 @@ const InstanceGoogleAuthenticationPage = observer(() => {
|
||||
return (
|
||||
<>
|
||||
<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="border-b border-custom-border-100 pb-3 space-y-1 flex-shrink-0">
|
||||
<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 mx-4 py-4 space-y-1 flex-shrink-0">
|
||||
<AuthenticationMethodCard
|
||||
name="Google"
|
||||
description="Allow members to login or sign up to plane with their Google
|
||||
@ -81,7 +81,7 @@ const InstanceGoogleAuthenticationPage = observer(() => {
|
||||
withBorder={false}
|
||||
/>
|
||||
</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 ? (
|
||||
<InstanceGoogleConfigForm config={formattedConfig} />
|
||||
) : (
|
||||
|
@ -119,14 +119,14 @@ const InstanceAuthenticationPage = observer(() => {
|
||||
return (
|
||||
<>
|
||||
<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="border-b border-custom-border-100 pb-3 space-y-1 flex-shrink-0">
|
||||
<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 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-sm font-normal text-custom-text-300">
|
||||
Configure authentication modes for your team and restrict sign ups to be invite only.
|
||||
</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 ? (
|
||||
<div className="space-y-3">
|
||||
<div className="text-lg font-medium">Authentication modes</div>
|
||||
|
@ -19,8 +19,8 @@ const InstanceEmailPage = observer(() => {
|
||||
return (
|
||||
<>
|
||||
<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="border-b border-custom-border-100 pb-3 space-y-1 flex-shrink-0">
|
||||
<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 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-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.
|
||||
@ -30,7 +30,7 @@ const InstanceEmailPage = observer(() => {
|
||||
</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 ? (
|
||||
<InstanceEmailForm config={formattedConfig} />
|
||||
) : (
|
||||
|
@ -51,7 +51,7 @@ export const SendTestEmailModal: FC<Props> = (props) => {
|
||||
setSendEmailStep(ESendEmailSteps.SUCCESS);
|
||||
})
|
||||
.catch((error) => {
|
||||
setError(error?.message || "Failed to send email");
|
||||
setError(error?.error || "Failed to send email");
|
||||
setSendEmailStep(ESendEmailSteps.FAILED);
|
||||
})
|
||||
.finally(() => {
|
||||
|
@ -10,15 +10,15 @@ function GeneralPage() {
|
||||
console.log("instance", instance);
|
||||
return (
|
||||
<>
|
||||
<div className="relative container mx-auto w-full h-full p-8 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="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 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-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
|
||||
instance.
|
||||
</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 && (
|
||||
<GeneralConfigurationForm instance={instance} instanceAdmins={instanceAdmins} />
|
||||
)}
|
||||
|
@ -332,42 +332,90 @@ body {
|
||||
}
|
||||
|
||||
/* scrollbar style */
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
@-moz-document url-prefix() {
|
||||
* {
|
||||
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 {
|
||||
overflow-x: scroll;
|
||||
.vertical-scrollbar {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.horizontal-scroll-enable::-webkit-scrollbar {
|
||||
.horizontal-scrollbar {
|
||||
overflow-x: auto;
|
||||
}
|
||||
.vertical-scrollbar::-webkit-scrollbar,
|
||||
.horizontal-scrollbar::-webkit-scrollbar {
|
||||
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 {
|
||||
height: 7px;
|
||||
background-color: rgba(var(--color-background-100));
|
||||
/* scrollbar sm size */
|
||||
.scrollbar-sm::-webkit-scrollbar {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
.horizontal-scroll-enable::-webkit-scrollbar-thumb {
|
||||
border-radius: 5px;
|
||||
background-color: rgba(var(--color-scrollbar));
|
||||
.scrollbar-sm::-webkit-scrollbar-thumb {
|
||||
border: 3px solid rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.vertical-scroll-enable::-webkit-scrollbar {
|
||||
display: block;
|
||||
width: 5px;
|
||||
/* scrollbar md size */
|
||||
.scrollbar-md::-webkit-scrollbar {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
.vertical-scroll-enable::-webkit-scrollbar-track {
|
||||
width: 5px;
|
||||
.scrollbar-md::-webkit-scrollbar-thumb {
|
||||
border: 3px solid rgba(0, 0, 0, 0);
|
||||
}
|
||||
/* scrollbar lg size */
|
||||
|
||||
.vertical-scroll-enable::-webkit-scrollbar-thumb {
|
||||
border-radius: 5px;
|
||||
background-color: rgba(var(--color-background-90));
|
||||
.scrollbar-lg::-webkit-scrollbar {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
.scrollbar-lg::-webkit-scrollbar-thumb {
|
||||
border: 4px solid rgba(0, 0, 0, 0);
|
||||
}
|
||||
/* end scrollbar style */
|
||||
|
||||
|
@ -19,14 +19,14 @@ const InstanceImagePage = observer(() => {
|
||||
return (
|
||||
<>
|
||||
<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="border-b border-custom-border-100 pb-3 space-y-1 flex-shrink-0">
|
||||
<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 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-sm font-normal text-custom-text-300">
|
||||
Let your users search and choose images from third-party libraries
|
||||
</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 ? (
|
||||
<InstanceImageConfigForm config={formattedConfig} />
|
||||
) : (
|
||||
|
@ -38,7 +38,7 @@ export const HelpSection: FC = observer(() => {
|
||||
// refs
|
||||
const helpOptionsRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const redirectionLink = encodeURI(WEB_BASE_URL + "/create-workspace");
|
||||
const redirectionLink = encodeURI(WEB_BASE_URL + "/");
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -56,7 +56,7 @@ export const SidebarMenu = observer(() => {
|
||||
};
|
||||
|
||||
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) => {
|
||||
const isActive = item.href === pathName || pathName.includes(item.href);
|
||||
return (
|
||||
|
@ -158,6 +158,7 @@ export const InstanceSetupForm: FC = (props) => {
|
||||
onError={() => setIsSubmitting(false)}
|
||||
>
|
||||
<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="w-full space-y-1">
|
||||
@ -319,8 +320,6 @@ export const InstanceSetupForm: FC = (props) => {
|
||||
<div>
|
||||
<Checkbox
|
||||
id="is_telemetry_enabled"
|
||||
name="is_telemetry_enabled"
|
||||
value={formData.is_telemetry_enabled ? "True" : "False"}
|
||||
onChange={() => handleFormChange("is_telemetry_enabled", !formData.is_telemetry_enabled)}
|
||||
checked={formData.is_telemetry_enabled}
|
||||
/>
|
||||
|
@ -7,9 +7,9 @@ import { useTheme as nextUseTheme } from "next-themes";
|
||||
// ui
|
||||
import { Button, getButtonStyling } from "@plane/ui";
|
||||
// helpers
|
||||
import { resolveGeneralTheme } from "helpers/common.helper";
|
||||
import { WEB_BASE_URL, resolveGeneralTheme } from "helpers/common.helper";
|
||||
// hooks
|
||||
import { useInstance, useTheme } from "@/hooks/store";
|
||||
import { useTheme } from "@/hooks/store";
|
||||
// icons
|
||||
import TakeoffIconLight from "/public/logos/takeoff-icon-light.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(() => {
|
||||
// hooks
|
||||
const { isNewUserPopup, toggleNewUserPopup } = useTheme();
|
||||
const { config } = useInstance();
|
||||
// theme
|
||||
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 <></>;
|
||||
return (
|
||||
|
@ -17,6 +17,7 @@ AUTHENTICATION_ERROR_CODES = {
|
||||
"INVALID_EMAIL_SIGN_UP": 5045,
|
||||
"INVALID_EMAIL_MAGIC_SIGN_UP": 5050,
|
||||
"MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED": 5055,
|
||||
"EMAIL_PASSWORD_AUTHENTICATION_DISABLED": 5056,
|
||||
# Sign In
|
||||
"USER_DOES_NOT_EXIST": 5060,
|
||||
"AUTHENTICATION_FAILED_SIGN_IN": 5065,
|
||||
|
@ -41,8 +41,10 @@ class EmailProvider(CredentialAdapter):
|
||||
|
||||
if ENABLE_EMAIL_PASSWORD == "0":
|
||||
raise AuthenticationException(
|
||||
error_code=AUTHENTICATION_ERROR_CODES["ENABLE_EMAIL_PASSWORD"],
|
||||
error_message="ENABLE_EMAIL_PASSWORD",
|
||||
error_code=AUTHENTICATION_ERROR_CODES[
|
||||
"EMAIL_PASSWORD_AUTHENTICATION_DISABLED"
|
||||
],
|
||||
error_message="EMAIL_PASSWORD_AUTHENTICATION_DISABLED",
|
||||
)
|
||||
|
||||
def set_user_data(self):
|
||||
|
@ -148,7 +148,7 @@ class InstanceEndpoint(BaseAPIView):
|
||||
data["app_base_url"] = settings.APP_BASE_URL
|
||||
|
||||
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}
|
||||
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 });
|
||||
|
||||
const issue = issuesMap[issueId];
|
||||
const subIssuesCount = issue.sub_issues_count;
|
||||
const subIssuesCount = issue?.sub_issues_count ?? 0;
|
||||
|
||||
const { isMobile } = usePlatformOS();
|
||||
|
||||
|
@ -63,7 +63,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||
const currentLayout = `${activeLayout} layout`;
|
||||
// derived values
|
||||
const stateDetails = getStateById(issue.state_id);
|
||||
const subIssueCount = issue.sub_issues_count;
|
||||
const subIssueCount = issue?.sub_issues_count ?? 0;
|
||||
|
||||
const issueOperations = useMemo(
|
||||
() => ({
|
||||
|
@ -19,7 +19,7 @@ export const SpreadsheetSubIssueColumn: React.FC<Props> = observer((props: Props
|
||||
// hooks
|
||||
const { workspaceSlug } = useAppRouter();
|
||||
// derived values
|
||||
const subIssueCount = issue.sub_issues_count;
|
||||
const subIssueCount = issue?.sub_issues_count ?? 0;
|
||||
|
||||
const redirectToIssueDetail = () => {
|
||||
router.push({
|
||||
|
@ -203,7 +203,7 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
|
||||
};
|
||||
|
||||
const disableUserActions = !canEditProperties(issueDetail.project_id);
|
||||
const subIssuesCount = issueDetail.sub_issues_count;
|
||||
const subIssuesCount = issueDetail?.sub_issues_count ?? 0;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -61,7 +61,7 @@ export const IssueListItem: React.FC<ISubIssues> = observer((props) => {
|
||||
undefined;
|
||||
|
||||
const subIssueHelpers = subIssueHelpersByIssueId(parentIssueId);
|
||||
const subIssueCount = issue?.sub_issues_count || 0;
|
||||
const subIssueCount = issue?.sub_issues_count ?? 0;
|
||||
|
||||
const handleIssuePeekOverview = (issue: TIssue) =>
|
||||
workspaceSlug &&
|
||||
|
@ -59,9 +59,8 @@ const calculateShades = (hexValue: string): 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;
|
||||
const dom = document?.querySelector<HTMLElement>("[data-theme='custom']");
|
||||
// palette: [bg, text, primary, sidebarBg, sidebarText]
|
||||
const values: string[] = palette.split(",");
|
||||
values.push(isDarkPalette ? "dark" : "light");
|
||||
|
@ -22,7 +22,7 @@ const StoreWrapper: FC<TStoreWrapper> = observer((props) => {
|
||||
const { sidebarCollapsed, toggleSidebar } = useAppTheme();
|
||||
const { data: userProfile } = useUserProfile();
|
||||
// states
|
||||
const [dom, setDom] = useState<undefined | HTMLElement>();
|
||||
const [dom, setDom] = useState<HTMLElement | null>(null);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (!userProfile?.theme?.theme) return;
|
||||
if (window) setDom(() => window.document?.querySelector<HTMLElement>("[data-theme='custom']") || undefined);
|
||||
|
||||
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(
|
||||
userProfile?.theme?.palette !== ",,,,"
|
||||
? userProfile?.theme?.palette
|
||||
: "#0d101b,#c5c5c5,#3f76ff,#0d101b,#c5c5c5",
|
||||
false
|
||||
false,
|
||||
dom
|
||||
);
|
||||
else unsetCustomCssVariables();
|
||||
}, [userProfile, userProfile?.theme?.theme, userProfile?.theme?.palette, setTheme, dom]);
|
||||
} else unsetCustomCssVariables();
|
||||
}, [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(() => {
|
||||
if (!router.query) return;
|
||||
|
@ -69,6 +69,10 @@ const nextConfig = {
|
||||
const ADMIN_BASE_URL = process.env.NEXT_PUBLIC_ADMIN_BASE_URL || "";
|
||||
const ADMIN_BASE_PATH = process.env.NEXT_PUBLIC_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({
|
||||
source: "/god-mode/: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);
|
||||
|
||||
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(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
response.id,
|
||||
data.module_ids,
|
||||
[]
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
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;
|
||||
} catch (error) {
|
||||
if (cycleId) this.fetchIssues(workspaceSlug, projectId, "mutation", cycleId);
|
||||
|
@ -111,8 +111,8 @@ export class IssueStore implements IIssueStore {
|
||||
|
||||
// store handlers from issue detail
|
||||
// parent
|
||||
if (issue && issue?.parent && issue?.parent?.id) {
|
||||
const parentIssue = await this.issueService.retrieve(workspaceSlug, projectId, issue?.parent?.id);
|
||||
if (issue && issue?.parent && issue?.parent?.id && issue?.parent?.project_id) {
|
||||
const parentIssue = await this.issueService.retrieve(workspaceSlug, issue.parent.project_id, issue?.parent?.id);
|
||||
this.rootIssueDetailStore.rootIssueStore.issues.addIssue([parentIssue]);
|
||||
}
|
||||
// assignees
|
||||
|
@ -294,17 +294,19 @@ export class ModuleIssues extends IssueHelperStore implements IModuleIssues {
|
||||
|
||||
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);
|
||||
if (quickAddIssueIndex >= 0)
|
||||
if (quickAddIssueIndex >= 0) {
|
||||
runInAction(() => {
|
||||
this.issues[moduleId].splice(quickAddIssueIndex, 1);
|
||||
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;
|
||||
} catch (error) {
|
||||
|
@ -239,24 +239,27 @@ export class ProjectViewIssues extends IssueHelperStore implements IProjectViewI
|
||||
|
||||
const response = await this.createIssue(workspaceSlug, projectId, data, viewId);
|
||||
|
||||
if (data.cycle_id && data.cycle_id !== "")
|
||||
await this.rootStore.cycleIssues.addIssueToCycle(workspaceSlug, projectId, data.cycle_id, [response.id]);
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
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(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
response.id,
|
||||
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;
|
||||
} catch (error) {
|
||||
|
@ -243,24 +243,29 @@ export class ProjectIssues extends IssueHelperStore implements IProjectIssues {
|
||||
|
||||
const response = await this.createIssue(workspaceSlug, projectId, data);
|
||||
|
||||
if (data.cycle_id && data.cycle_id !== "")
|
||||
await this.rootStore.cycleIssues.addIssueToCycle(workspaceSlug, projectId, data.cycle_id, [response.id]);
|
||||
const quickAddIssueIndex = this.issues[projectId].findIndex((_issueId) => _issueId === data.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(
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
response.id,
|
||||
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;
|
||||
} catch (error) {
|
||||
this.fetchIssues(workspaceSlug, projectId, "mutation");
|
||||
|
Loading…
Reference in New Issue
Block a user