mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: environment config changes in the API are replicated in web and space app (#2699)
* fix: envconfig type changes * chore: configuration variables (#2692) * chore: update avatar group logic (#2672) * chore: configuration variables --------- * fix: replacing slack client id with env config --------- Co-authored-by: Nikhil <118773738+pablohashescobar@users.noreply.github.com>
This commit is contained in:
parent
1986c0dfd4
commit
26de35bd8d
@ -21,8 +21,8 @@ class ConfigurationEndpoint(BaseAPIView):
|
|||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
data = {}
|
data = {}
|
||||||
data["google"] = os.environ.get("GOOGLE_CLIENT_ID", None)
|
data["google_client_id"] = os.environ.get("GOOGLE_CLIENT_ID", None)
|
||||||
data["github"] = os.environ.get("GITHUB_CLIENT_ID", None)
|
data["github_client_id"] = os.environ.get("GITHUB_CLIENT_ID", None)
|
||||||
data["github_app_name"] = os.environ.get("GITHUB_APP_NAME", None)
|
data["github_app_name"] = os.environ.get("GITHUB_APP_NAME", None)
|
||||||
data["magic_login"] = (
|
data["magic_login"] = (
|
||||||
bool(settings.EMAIL_HOST_USER) and bool(settings.EMAIL_HOST_PASSWORD)
|
bool(settings.EMAIL_HOST_USER) and bool(settings.EMAIL_HOST_PASSWORD)
|
||||||
@ -30,5 +30,5 @@ class ConfigurationEndpoint(BaseAPIView):
|
|||||||
data["email_password_login"] = (
|
data["email_password_login"] = (
|
||||||
os.environ.get("ENABLE_EMAIL_PASSWORD", "0") == "1"
|
os.environ.get("ENABLE_EMAIL_PASSWORD", "0") == "1"
|
||||||
)
|
)
|
||||||
data["slack"] = os.environ.get("SLACK_CLIENT_ID", None)
|
data["slack_client_id"] = os.environ.get("SLACK_CLIENT_ID", None)
|
||||||
return Response(data, status=status.HTTP_200_OK)
|
return Response(data, status=status.HTTP_200_OK)
|
||||||
|
@ -116,7 +116,9 @@ export const SignInView = observer(() => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex flex-col items-center justify-center gap-4 pt-7 sm:w-[360px] mx-auto overflow-hidden">
|
<div className="flex flex-col items-center justify-center gap-4 pt-7 sm:w-[360px] mx-auto overflow-hidden">
|
||||||
{data?.google && <GoogleLoginButton clientId={data.google} handleSignIn={handleGoogleSignIn} />}
|
{data?.google_client_id && (
|
||||||
|
<GoogleLoginButton clientId={data.google_client_id} handleSignIn={handleGoogleSignIn} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="pt-16 text-custom-text-200 text-sm text-center">
|
<p className="pt-16 text-custom-text-200 text-sm text-center">
|
||||||
|
@ -3,12 +3,13 @@ import APIService from "services/api.service";
|
|||||||
// helper
|
// helper
|
||||||
import { API_BASE_URL } from "helpers/common.helper";
|
import { API_BASE_URL } from "helpers/common.helper";
|
||||||
|
|
||||||
export interface IEnvConfig {
|
export interface IAppConfig {
|
||||||
github: string;
|
|
||||||
google: string;
|
|
||||||
github_app_name: string | null;
|
|
||||||
email_password_login: boolean;
|
email_password_login: boolean;
|
||||||
|
google_client_id: string | null;
|
||||||
|
github_app_name: string | null;
|
||||||
|
github_client_id: string | null;
|
||||||
magic_login: boolean;
|
magic_login: boolean;
|
||||||
|
slack_client_id: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AppConfigService extends APIService {
|
export class AppConfigService extends APIService {
|
||||||
@ -16,7 +17,7 @@ export class AppConfigService extends APIService {
|
|||||||
super(API_BASE_URL);
|
super(API_BASE_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
async envConfig(): Promise<IEnvConfig> {
|
async envConfig(): Promise<IAppConfig> {
|
||||||
return this.get("/api/configs/", {
|
return this.get("/api/configs/", {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
"NEXT_PUBLIC_DEPLOY_URL",
|
"NEXT_PUBLIC_DEPLOY_URL",
|
||||||
"NEXT_PUBLIC_SENTRY_DSN",
|
"NEXT_PUBLIC_SENTRY_DSN",
|
||||||
"NEXT_PUBLIC_SENTRY_ENVIRONMENT",
|
"NEXT_PUBLIC_SENTRY_ENVIRONMENT",
|
||||||
"NEXT_PUBLIC_GITHUB_APP_NAME",
|
|
||||||
"NEXT_PUBLIC_ENABLE_SENTRY",
|
"NEXT_PUBLIC_ENABLE_SENTRY",
|
||||||
"NEXT_PUBLIC_ENABLE_OAUTH",
|
"NEXT_PUBLIC_ENABLE_OAUTH",
|
||||||
"NEXT_PUBLIC_TRACK_EVENTS",
|
"NEXT_PUBLIC_TRACK_EVENTS",
|
||||||
@ -22,8 +21,7 @@
|
|||||||
"SLACK_CLIENT_SECRET",
|
"SLACK_CLIENT_SECRET",
|
||||||
"JITSU_TRACKER_ACCESS_KEY",
|
"JITSU_TRACKER_ACCESS_KEY",
|
||||||
"JITSU_TRACKER_HOST",
|
"JITSU_TRACKER_HOST",
|
||||||
"UNSPLASH_ACCESS_KEY",
|
"UNSPLASH_ACCESS_KEY"
|
||||||
"NEXT_PUBLIC_SLACK_CLIENT_ID"
|
|
||||||
],
|
],
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"build": {
|
"build": {
|
||||||
|
@ -4,14 +4,24 @@ import useIntegrationPopup from "hooks/use-integration-popup";
|
|||||||
import { Button } from "@plane/ui";
|
import { Button } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IWorkspaceIntegration } from "types";
|
import { IWorkspaceIntegration } from "types";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
workspaceIntegration: false | IWorkspaceIntegration | undefined;
|
workspaceIntegration: false | IWorkspaceIntegration | undefined;
|
||||||
provider: string | undefined;
|
provider: string | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GithubAuth: React.FC<Props> = ({ workspaceIntegration, provider }) => {
|
export const GithubAuth: React.FC<Props> = observer(({ workspaceIntegration, provider }) => {
|
||||||
const { startAuth, isConnecting } = useIntegrationPopup(provider);
|
const {
|
||||||
|
appConfig: { envConfig },
|
||||||
|
} = useMobxStore();
|
||||||
|
// hooks
|
||||||
|
const { startAuth, isConnecting } = useIntegrationPopup({
|
||||||
|
provider,
|
||||||
|
github_app_name: envConfig?.github_app_name || "",
|
||||||
|
slack_client_id: envConfig?.slack_client_id || "",
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -26,4 +36,4 @@ export const GithubAuth: React.FC<Props> = ({ workspaceIntegration, provider })
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -20,6 +20,8 @@ import { CheckCircle } from "lucide-react";
|
|||||||
import { IAppIntegration, IWorkspaceIntegration } from "types";
|
import { IAppIntegration, IWorkspaceIntegration } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { WORKSPACE_INTEGRATIONS } from "constants/fetch-keys";
|
import { WORKSPACE_INTEGRATIONS } from "constants/fetch-keys";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
integration: IAppIntegration;
|
integration: IAppIntegration;
|
||||||
@ -41,7 +43,11 @@ const integrationDetails: { [key: string]: any } = {
|
|||||||
// services
|
// services
|
||||||
const integrationService = new IntegrationService();
|
const integrationService = new IntegrationService();
|
||||||
|
|
||||||
export const SingleIntegrationCard: React.FC<Props> = ({ integration }) => {
|
export const SingleIntegrationCard: React.FC<Props> = observer(({ integration }) => {
|
||||||
|
const {
|
||||||
|
appConfig: { envConfig },
|
||||||
|
} = useMobxStore();
|
||||||
|
|
||||||
const [deletingIntegration, setDeletingIntegration] = useState(false);
|
const [deletingIntegration, setDeletingIntegration] = useState(false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -49,7 +55,11 @@ export const SingleIntegrationCard: React.FC<Props> = ({ integration }) => {
|
|||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const { startAuth, isConnecting: isInstalling } = useIntegrationPopup(integration.provider);
|
const { startAuth, isConnecting: isInstalling } = useIntegrationPopup({
|
||||||
|
provider: integration.provider,
|
||||||
|
github_app_name: envConfig?.github_app_name || "",
|
||||||
|
slack_client_id: envConfig?.slack_client_id || "",
|
||||||
|
});
|
||||||
|
|
||||||
const { data: workspaceIntegrations } = useSWR(
|
const { data: workspaceIntegrations } = useSWR(
|
||||||
workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug as string) : null,
|
workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug as string) : null,
|
||||||
@ -132,4 +142,4 @@ export const SingleIntegrationCard: React.FC<Props> = ({ integration }) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
// services
|
// services
|
||||||
import { AppInstallationService } from "services/app_installation.service";
|
import { AppInstallationService } from "services/app_installation.service";
|
||||||
// ui
|
// ui
|
||||||
@ -11,6 +12,8 @@ import useIntegrationPopup from "hooks/use-integration-popup";
|
|||||||
import { IWorkspaceIntegration, ISlackIntegration } from "types";
|
import { IWorkspaceIntegration, ISlackIntegration } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { SLACK_CHANNEL_INFO } from "constants/fetch-keys";
|
import { SLACK_CHANNEL_INFO } from "constants/fetch-keys";
|
||||||
|
// lib
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
integration: IWorkspaceIntegration;
|
integration: IWorkspaceIntegration;
|
||||||
@ -18,14 +21,24 @@ type Props = {
|
|||||||
|
|
||||||
const appInstallationService = new AppInstallationService();
|
const appInstallationService = new AppInstallationService();
|
||||||
|
|
||||||
export const SelectChannel: React.FC<Props> = ({ integration }) => {
|
export const SelectChannel: React.FC<Props> = observer(({ integration }) => {
|
||||||
|
// store
|
||||||
|
const {
|
||||||
|
appConfig: { envConfig },
|
||||||
|
} = useMobxStore();
|
||||||
|
// states
|
||||||
const [slackChannelAvailabilityToggle, setSlackChannelAvailabilityToggle] = useState<boolean>(false);
|
const [slackChannelAvailabilityToggle, setSlackChannelAvailabilityToggle] = useState<boolean>(false);
|
||||||
const [slackChannel, setSlackChannel] = useState<ISlackIntegration | null>(null);
|
const [slackChannel, setSlackChannel] = useState<ISlackIntegration | null>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const { startAuth } = useIntegrationPopup("slackChannel", integration.id);
|
const { startAuth } = useIntegrationPopup({
|
||||||
|
provider: "slackChannel",
|
||||||
|
stateParams: integration.id,
|
||||||
|
github_app_name: envConfig?.github_client_id || "",
|
||||||
|
slack_client_id: envConfig?.slack_client_id || "",
|
||||||
|
});
|
||||||
|
|
||||||
const { data: projectIntegration } = useSWR(
|
const { data: projectIntegration } = useSWR(
|
||||||
workspaceSlug && projectId && integration.id
|
workspaceSlug && projectId && integration.id
|
||||||
@ -97,4 +110,4 @@ export const SelectChannel: React.FC<Props> = ({ integration }) => {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { useState, useEffect, useCallback } from "react";
|
import { useState, useEffect, useCallback } from "react";
|
||||||
import useSWR from "swr";
|
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
@ -8,7 +7,6 @@ import useToast from "hooks/use-toast";
|
|||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// services
|
// services
|
||||||
import { AuthService } from "services/auth.service";
|
import { AuthService } from "services/auth.service";
|
||||||
import { AppConfigService } from "services/app_config.service";
|
|
||||||
// components
|
// components
|
||||||
import {
|
import {
|
||||||
GoogleLoginButton,
|
GoogleLoginButton,
|
||||||
@ -24,12 +22,12 @@ import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png";
|
|||||||
// types
|
// types
|
||||||
import { IUser, IUserSettings } from "types";
|
import { IUser, IUserSettings } from "types";
|
||||||
|
|
||||||
const appConfigService = new AppConfigService();
|
|
||||||
const authService = new AuthService();
|
const authService = new AuthService();
|
||||||
|
|
||||||
export const SignInView = observer(() => {
|
export const SignInView = observer(() => {
|
||||||
const {
|
const {
|
||||||
user: { fetchCurrentUser, fetchCurrentUserSettings },
|
user: { fetchCurrentUser, fetchCurrentUserSettings },
|
||||||
|
appConfig: { envConfig },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -38,12 +36,16 @@ export const SignInView = observer(() => {
|
|||||||
const [isLoading, setLoading] = useState(false);
|
const [isLoading, setLoading] = useState(false);
|
||||||
// toast
|
// toast
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
// fetch app config
|
|
||||||
const { data, error: appConfigError } = useSWR("APP_CONFIG", () => appConfigService.envConfig());
|
|
||||||
// computed
|
// computed
|
||||||
const enableEmailPassword =
|
const enableEmailPassword =
|
||||||
data &&
|
envConfig &&
|
||||||
(data?.email_password_login || !(data?.email_password_login || data?.magic_login || data?.google || data?.github));
|
(envConfig?.email_password_login ||
|
||||||
|
!(
|
||||||
|
envConfig?.email_password_login ||
|
||||||
|
envConfig?.magic_login ||
|
||||||
|
envConfig?.google_client_id ||
|
||||||
|
envConfig?.github_client_id
|
||||||
|
));
|
||||||
|
|
||||||
const handleLoginRedirection = useCallback(
|
const handleLoginRedirection = useCallback(
|
||||||
(user: IUser) => {
|
(user: IUser) => {
|
||||||
@ -114,11 +116,11 @@ export const SignInView = observer(() => {
|
|||||||
const handleGitHubSignIn = async (credential: string) => {
|
const handleGitHubSignIn = async (credential: string) => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
if (data && data.github && credential) {
|
if (envConfig && envConfig.github_client_id && credential) {
|
||||||
const socialAuthPayload = {
|
const socialAuthPayload = {
|
||||||
medium: "github",
|
medium: "github",
|
||||||
credential,
|
credential,
|
||||||
clientId: data.github,
|
clientId: envConfig.github_client_id,
|
||||||
};
|
};
|
||||||
const response = await authService.socialAuth(socialAuthPayload);
|
const response = await authService.socialAuth(socialAuthPayload);
|
||||||
if (response) {
|
if (response) {
|
||||||
@ -195,7 +197,7 @@ export const SignInView = observer(() => {
|
|||||||
Sign in to Plane
|
Sign in to Plane
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
{!data && !appConfigError ? (
|
{!envConfig ? (
|
||||||
<div className="pt-10 w-ful">
|
<div className="pt-10 w-ful">
|
||||||
<Loader className="space-y-4 w-full pb-4">
|
<Loader className="space-y-4 w-full pb-4">
|
||||||
<Loader.Item height="46px" width="360px" />
|
<Loader.Item height="46px" width="360px" />
|
||||||
@ -211,7 +213,7 @@ export const SignInView = observer(() => {
|
|||||||
<>
|
<>
|
||||||
<>
|
<>
|
||||||
{enableEmailPassword && <EmailPasswordForm onSubmit={handlePasswordSignIn} />}
|
{enableEmailPassword && <EmailPasswordForm onSubmit={handlePasswordSignIn} />}
|
||||||
{data?.magic_login && (
|
{envConfig?.magic_login && (
|
||||||
<div className="flex flex-col divide-y divide-custom-border-200">
|
<div className="flex flex-col divide-y divide-custom-border-200">
|
||||||
<div className="pb-7">
|
<div className="pb-7">
|
||||||
<EmailCodeForm handleSignIn={handleEmailCodeSignIn} />
|
<EmailCodeForm handleSignIn={handleEmailCodeSignIn} />
|
||||||
@ -219,8 +221,12 @@ export const SignInView = observer(() => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex flex-col items-center justify-center gap-4 pt-7 sm:w-[360px] mx-auto overflow-hidden">
|
<div className="flex flex-col items-center justify-center gap-4 pt-7 sm:w-[360px] mx-auto overflow-hidden">
|
||||||
{data?.google && <GoogleLoginButton clientId={data?.google} handleSignIn={handleGoogleSignIn} />}
|
{envConfig?.google_client_id && (
|
||||||
{data?.github && <GithubLoginButton clientId={data?.github} handleSignIn={handleGitHubSignIn} />}
|
<GoogleLoginButton clientId={envConfig?.google_client_id} handleSignIn={handleGoogleSignIn} />
|
||||||
|
)}
|
||||||
|
{envConfig?.github_client_id && (
|
||||||
|
<GithubLoginButton clientId={envConfig?.github_client_id} handleSignIn={handleGitHubSignIn} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
<p className="pt-16 text-custom-text-200 text-sm text-center">
|
<p className="pt-16 text-custom-text-200 text-sm text-center">
|
||||||
|
@ -1,23 +1,26 @@
|
|||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
const useIntegrationPopup = (provider: string | undefined, stateParams?: string) => {
|
const useIntegrationPopup = ({
|
||||||
|
provider,
|
||||||
|
stateParams,
|
||||||
|
github_app_name,
|
||||||
|
slack_client_id,
|
||||||
|
}: {
|
||||||
|
provider: string | undefined;
|
||||||
|
stateParams?: string;
|
||||||
|
github_app_name?: string;
|
||||||
|
slack_client_id?: string;
|
||||||
|
}) => {
|
||||||
const [authLoader, setAuthLoader] = useState(false);
|
const [authLoader, setAuthLoader] = useState(false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const providerUrls: { [key: string]: string } = {
|
const providerUrls: { [key: string]: string } = {
|
||||||
github: `https://github.com/apps/${
|
github: `https://github.com/apps/${github_app_name}/installations/new?state=${workspaceSlug?.toString()}`,
|
||||||
process.env.NEXT_PUBLIC_GITHUB_APP_NAME
|
slack: `https://slack.com/oauth/v2/authorize?scope=chat:write,im:history,im:write,links:read,links:write,users:read,users:read.email&user_scope=&&client_id=${slack_client_id}&state=${workspaceSlug?.toString()}`,
|
||||||
}/installations/new?state=${workspaceSlug?.toString()}`,
|
slackChannel: `https://slack.com/oauth/v2/authorize?scope=incoming-webhook&client_id=${slack_client_id}&state=${workspaceSlug?.toString()},${projectId?.toString()}${
|
||||||
slack: `https://slack.com/oauth/v2/authorize?scope=chat:write,im:history,im:write,links:read,links:write,users:read,users:read.email&user_scope=&&client_id=${
|
|
||||||
process.env.NEXT_PUBLIC_SLACK_CLIENT_ID
|
|
||||||
}&state=${workspaceSlug?.toString()}`,
|
|
||||||
slackChannel: `https://slack.com/oauth/v2/authorize?scope=incoming-webhook&client_id=${
|
|
||||||
process.env.NEXT_PUBLIC_SLACK_CLIENT_ID
|
|
||||||
}&state=${workspaceSlug?.toString()},${projectId?.toString()}${
|
|
||||||
stateParams ? "," + stateParams : ""
|
stateParams ? "," + stateParams : ""
|
||||||
}`,
|
}`,
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
// next themes
|
import { observer } from "mobx-react-lite";
|
||||||
|
import useSWR from "swr";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
// mobx store
|
// mobx store
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import { useRouter } from "next/router";
|
// helpers
|
||||||
import { applyTheme, unsetCustomCssVariables } from "helpers/theme.helper";
|
import { applyTheme, unsetCustomCssVariables } from "helpers/theme.helper";
|
||||||
import { observer } from "mobx-react-lite";
|
|
||||||
|
|
||||||
const MobxStoreInit = observer(() => {
|
const MobxStoreInit = observer(() => {
|
||||||
// router
|
// router
|
||||||
@ -13,16 +14,19 @@ const MobxStoreInit = observer(() => {
|
|||||||
const { workspaceSlug, projectId, cycleId, moduleId, globalViewId, viewId, inboxId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId, globalViewId, viewId, inboxId } = router.query;
|
||||||
// store
|
// store
|
||||||
const {
|
const {
|
||||||
theme: themeStore,
|
theme: { sidebarCollapsed, toggleSidebar },
|
||||||
user: userStore,
|
user: { currentUser },
|
||||||
workspace: workspaceStore,
|
workspace: { setWorkspaceSlug },
|
||||||
project: projectStore,
|
project: { setProjectId },
|
||||||
cycle: cycleStore,
|
cycle: { setCycleId },
|
||||||
module: moduleStore,
|
module: { setModuleId },
|
||||||
globalViews: globalViewsStore,
|
globalViews: { setGlobalViewId },
|
||||||
projectViews: projectViewsStore,
|
projectViews: { setViewId },
|
||||||
inbox: inboxStore,
|
inbox: { setInboxId },
|
||||||
|
appConfig: { fetchAppConfig },
|
||||||
} = useMobxStore();
|
} = useMobxStore();
|
||||||
|
// fetching application Config
|
||||||
|
useSWR("APP_CONFIG", () => fetchAppConfig(), { revalidateIfStale: false, revalidateOnFocus: false });
|
||||||
// state
|
// state
|
||||||
const [dom, setDom] = useState<any>();
|
const [dom, setDom] = useState<any>();
|
||||||
// theme
|
// theme
|
||||||
@ -34,36 +38,36 @@ const MobxStoreInit = observer(() => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const localValue = localStorage && localStorage.getItem("app_sidebar_collapsed");
|
const localValue = localStorage && localStorage.getItem("app_sidebar_collapsed");
|
||||||
const localBoolValue = localValue ? (localValue === "true" ? true : false) : false;
|
const localBoolValue = localValue ? (localValue === "true" ? true : false) : false;
|
||||||
if (localValue && themeStore?.sidebarCollapsed === undefined) {
|
if (localValue && sidebarCollapsed === undefined) {
|
||||||
themeStore.toggleSidebar(localBoolValue);
|
toggleSidebar(localBoolValue);
|
||||||
}
|
}
|
||||||
}, [themeStore, userStore, setTheme]);
|
}, [sidebarCollapsed, currentUser, setTheme, toggleSidebar]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 (!userStore.currentUser) return;
|
if (!currentUser) return;
|
||||||
if (window) {
|
if (window) {
|
||||||
setDom(window.document?.querySelector<HTMLElement>("[data-theme='custom']"));
|
setDom(window.document?.querySelector<HTMLElement>("[data-theme='custom']"));
|
||||||
}
|
}
|
||||||
setTheme(userStore.currentUser?.theme?.theme || "system");
|
setTheme(currentUser?.theme?.theme || "system");
|
||||||
if (userStore.currentUser?.theme?.theme === "custom" && dom) {
|
if (currentUser?.theme?.theme === "custom" && dom) {
|
||||||
applyTheme(userStore.currentUser?.theme?.palette, false);
|
applyTheme(currentUser?.theme?.palette, false);
|
||||||
} else unsetCustomCssVariables();
|
} else unsetCustomCssVariables();
|
||||||
}, [userStore.currentUser, setTheme, dom]);
|
}, [currentUser, setTheme, dom]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setting router info to the respective stores.
|
* Setting router info to the respective stores.
|
||||||
*/
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (workspaceSlug) workspaceStore.setWorkspaceSlug(workspaceSlug.toString());
|
if (workspaceSlug) setWorkspaceSlug(workspaceSlug.toString());
|
||||||
if (projectId) projectStore.setProjectId(projectId.toString());
|
if (projectId) setProjectId(projectId.toString());
|
||||||
if (cycleId) cycleStore.setCycleId(cycleId.toString());
|
if (cycleId) setCycleId(cycleId.toString());
|
||||||
if (moduleId) moduleStore.setModuleId(moduleId.toString());
|
if (moduleId) setModuleId(moduleId.toString());
|
||||||
if (globalViewId) globalViewsStore.setGlobalViewId(globalViewId.toString());
|
if (globalViewId) setGlobalViewId(globalViewId.toString());
|
||||||
if (viewId) projectViewsStore.setViewId(viewId.toString());
|
if (viewId) setViewId(viewId.toString());
|
||||||
if (inboxId) inboxStore.setInboxId(inboxId.toString());
|
if (inboxId) setInboxId(inboxId.toString());
|
||||||
}, [
|
}, [
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
@ -72,13 +76,13 @@ const MobxStoreInit = observer(() => {
|
|||||||
globalViewId,
|
globalViewId,
|
||||||
viewId,
|
viewId,
|
||||||
inboxId,
|
inboxId,
|
||||||
workspaceStore,
|
setWorkspaceSlug,
|
||||||
projectStore,
|
setProjectId,
|
||||||
cycleStore,
|
setCycleId,
|
||||||
moduleStore,
|
setModuleId,
|
||||||
globalViewsStore,
|
setGlobalViewId,
|
||||||
projectViewsStore,
|
setViewId,
|
||||||
inboxStore,
|
setInboxId,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
|
@ -2,27 +2,21 @@
|
|||||||
import { APIService } from "services/api.service";
|
import { APIService } from "services/api.service";
|
||||||
// helper
|
// helper
|
||||||
import { API_BASE_URL } from "helpers/common.helper";
|
import { API_BASE_URL } from "helpers/common.helper";
|
||||||
|
// types
|
||||||
export interface IEnvConfig {
|
import { IAppConfig } from "types/app";
|
||||||
github: string;
|
|
||||||
google: string;
|
|
||||||
github_app_name: string | null;
|
|
||||||
email_password_login: boolean;
|
|
||||||
magic_login: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AppConfigService extends APIService {
|
export class AppConfigService extends APIService {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(API_BASE_URL);
|
super(API_BASE_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
async envConfig(): Promise<IEnvConfig> {
|
async envConfig(): Promise<IAppConfig> {
|
||||||
return this.get("/api/configs/", {
|
return this.get("/api/configs/", {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((response) => response?.data)
|
.then((response) => response.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
throw error?.response?.data;
|
throw error?.response?.data;
|
||||||
});
|
});
|
||||||
|
47
web/store/app-config.store.ts
Normal file
47
web/store/app-config.store.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { observable, action, makeObservable, runInAction } from "mobx";
|
||||||
|
// types
|
||||||
|
import { RootStore } from "./root";
|
||||||
|
import { IAppConfig } from "types/app";
|
||||||
|
// services
|
||||||
|
import { AppConfigService } from "services/app_config.service";
|
||||||
|
|
||||||
|
export interface IAppConfigStore {
|
||||||
|
envConfig: IAppConfig | null;
|
||||||
|
// action
|
||||||
|
fetchAppConfig: () => Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppConfigStore implements IAppConfigStore {
|
||||||
|
// observables
|
||||||
|
envConfig: IAppConfig | null = null;
|
||||||
|
|
||||||
|
// root store
|
||||||
|
rootStore;
|
||||||
|
// service
|
||||||
|
appConfigService;
|
||||||
|
|
||||||
|
constructor(_rootStore: RootStore) {
|
||||||
|
makeObservable(this, {
|
||||||
|
// observables
|
||||||
|
envConfig: observable.ref,
|
||||||
|
// actions
|
||||||
|
fetchAppConfig: action,
|
||||||
|
});
|
||||||
|
this.appConfigService = new AppConfigService();
|
||||||
|
|
||||||
|
this.rootStore = _rootStore;
|
||||||
|
}
|
||||||
|
fetchAppConfig = async () => {
|
||||||
|
try {
|
||||||
|
const config = await this.appConfigService.envConfig();
|
||||||
|
runInAction(() => {
|
||||||
|
this.envConfig = config;
|
||||||
|
});
|
||||||
|
return config;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AppConfigStore;
|
@ -1,5 +1,6 @@
|
|||||||
import { enableStaticRendering } from "mobx-react-lite";
|
import { enableStaticRendering } from "mobx-react-lite";
|
||||||
// store imports
|
// store imports
|
||||||
|
import AppConfigStore, { IAppConfigStore } from "./app-config.store";
|
||||||
import CommandPaletteStore, { ICommandPaletteStore } from "./command-palette.store";
|
import CommandPaletteStore, { ICommandPaletteStore } from "./command-palette.store";
|
||||||
import UserStore, { IUserStore } from "store/user.store";
|
import UserStore, { IUserStore } from "store/user.store";
|
||||||
import ThemeStore, { IThemeStore } from "store/theme.store";
|
import ThemeStore, { IThemeStore } from "store/theme.store";
|
||||||
@ -107,6 +108,7 @@ enableStaticRendering(typeof window === "undefined");
|
|||||||
export class RootStore {
|
export class RootStore {
|
||||||
user: IUserStore;
|
user: IUserStore;
|
||||||
theme: IThemeStore;
|
theme: IThemeStore;
|
||||||
|
appConfig: IAppConfigStore;
|
||||||
|
|
||||||
commandPalette: ICommandPaletteStore;
|
commandPalette: ICommandPaletteStore;
|
||||||
workspace: IWorkspaceStore;
|
workspace: IWorkspaceStore;
|
||||||
@ -167,6 +169,7 @@ export class RootStore {
|
|||||||
mentionsStore: IMentionsStore;
|
mentionsStore: IMentionsStore;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this.appConfig = new AppConfigStore(this);
|
||||||
this.commandPalette = new CommandPaletteStore(this);
|
this.commandPalette = new CommandPaletteStore(this);
|
||||||
this.user = new UserStore(this);
|
this.user = new UserStore(this);
|
||||||
this.theme = new ThemeStore(this);
|
this.theme = new ThemeStore(this);
|
||||||
|
9
web/types/app.d.ts
vendored
9
web/types/app.d.ts
vendored
@ -1,3 +1,12 @@
|
|||||||
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
|
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
|
||||||
getLayout?: (page: ReactElement) => ReactNode;
|
getLayout?: (page: ReactElement) => ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface IAppConfig {
|
||||||
|
email_password_login: boolean;
|
||||||
|
google_client_id: string | null;
|
||||||
|
github_app_name: string | null;
|
||||||
|
github_client_id: string | null;
|
||||||
|
magic_login: boolean;
|
||||||
|
slack_client_id: string | null;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user