Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apiserver/plane/api/views/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ class ConfigurationEndpoint(BaseAPIView):

def get(self, request):
data = {}
data["google"] = os.environ.get("GOOGLE_CLIENT_ID", None)
data["github"] = os.environ.get("GITHUB_CLIENT_ID", None)
data["google_client_id"] = os.environ.get("GOOGLE_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["magic_login"] = (
bool(settings.EMAIL_HOST_USER) and bool(settings.EMAIL_HOST_PASSWORD)
) and os.environ.get("ENABLE_MAGIC_LINK_LOGIN", "0") == "1"
data["email_password_login"] = (
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)
4 changes: 3 additions & 1 deletion space/components/accounts/sign-in.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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">
{data?.google && <GoogleLoginButton clientId={data.google} handleSignIn={handleGoogleSignIn} />}
{data?.google_client_id && (
<GoogleLoginButton clientId={data.google_client_id} handleSignIn={handleGoogleSignIn} />
)}
</div>

<p className="pt-16 text-custom-text-200 text-sm text-center">
Expand Down
11 changes: 6 additions & 5 deletions space/services/app-config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@ import APIService from "services/api.service";
// helper
import { API_BASE_URL } from "helpers/common.helper";

export interface IEnvConfig {
github: string;
google: string;
github_app_name: string | null;
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;
}

export class AppConfigService extends APIService {
constructor() {
super(API_BASE_URL);
}

async envConfig(): Promise<IEnvConfig> {
async envConfig(): Promise<IAppConfig> {
return this.get("/api/configs/", {
headers: {
"Content-Type": "application/json",
Expand Down
4 changes: 1 addition & 3 deletions turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"NEXT_PUBLIC_DEPLOY_URL",
"NEXT_PUBLIC_SENTRY_DSN",
"NEXT_PUBLIC_SENTRY_ENVIRONMENT",
"NEXT_PUBLIC_GITHUB_APP_NAME",
"NEXT_PUBLIC_ENABLE_SENTRY",
"NEXT_PUBLIC_ENABLE_OAUTH",
"NEXT_PUBLIC_TRACK_EVENTS",
Expand All @@ -22,8 +21,7 @@
"SLACK_CLIENT_SECRET",
"JITSU_TRACKER_ACCESS_KEY",
"JITSU_TRACKER_HOST",
"UNSPLASH_ACCESS_KEY",
"NEXT_PUBLIC_SLACK_CLIENT_ID"
"UNSPLASH_ACCESS_KEY"
],
"pipeline": {
"build": {
Expand Down
16 changes: 13 additions & 3 deletions web/components/integration/github/auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,24 @@ import useIntegrationPopup from "hooks/use-integration-popup";
import { Button } from "@plane/ui";
// types
import { IWorkspaceIntegration } from "types";
import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";

type Props = {
workspaceIntegration: false | IWorkspaceIntegration | undefined;
provider: string | undefined;
};

export const GithubAuth: React.FC<Props> = ({ workspaceIntegration, provider }) => {
const { startAuth, isConnecting } = useIntegrationPopup(provider);
export const GithubAuth: React.FC<Props> = observer(({ workspaceIntegration, 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 (
<div>
Expand All @@ -26,4 +36,4 @@ export const GithubAuth: React.FC<Props> = ({ workspaceIntegration, provider })
)}
</div>
);
};
});
16 changes: 13 additions & 3 deletions web/components/integration/single-integration-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { CheckCircle } from "lucide-react";
import { IAppIntegration, IWorkspaceIntegration } from "types";
// fetch-keys
import { WORKSPACE_INTEGRATIONS } from "constants/fetch-keys";
import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";

type Props = {
integration: IAppIntegration;
Expand All @@ -41,15 +43,23 @@ const integrationDetails: { [key: string]: any } = {
// services
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 router = useRouter();
const { workspaceSlug } = router.query;

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(
workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug as string) : null,
Expand Down Expand Up @@ -132,4 +142,4 @@ export const SingleIntegrationCard: React.FC<Props> = ({ integration }) => {
)}
</div>
);
};
});
19 changes: 16 additions & 3 deletions web/components/integration/slack/select-channel.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import useSWR, { mutate } from "swr";
import { observer } from "mobx-react-lite";
// services
import { AppInstallationService } from "services/app_installation.service";
// ui
Expand All @@ -11,21 +12,33 @@ import useIntegrationPopup from "hooks/use-integration-popup";
import { IWorkspaceIntegration, ISlackIntegration } from "types";
// fetch-keys
import { SLACK_CHANNEL_INFO } from "constants/fetch-keys";
// lib
import { useMobxStore } from "lib/mobx/store-provider";

type Props = {
integration: IWorkspaceIntegration;
};

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 [slackChannel, setSlackChannel] = useState<ISlackIntegration | null>(null);

const router = useRouter();
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(
workspaceSlug && projectId && integration.id
Expand Down Expand Up @@ -97,4 +110,4 @@ export const SelectChannel: React.FC<Props> = ({ integration }) => {
)}
</>
);
};
});
32 changes: 19 additions & 13 deletions web/components/page-views/signin.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useState, useEffect, useCallback } from "react";
import useSWR from "swr";
import { observer } from "mobx-react-lite";
import Image from "next/image";
import { useRouter } from "next/router";
Expand All @@ -8,7 +7,6 @@ import useToast from "hooks/use-toast";
import { useMobxStore } from "lib/mobx/store-provider";
// services
import { AuthService } from "services/auth.service";
import { AppConfigService } from "services/app_config.service";
// components
import {
GoogleLoginButton,
Expand All @@ -24,12 +22,12 @@ import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png";
// types
import { IUser, IUserSettings } from "types";

const appConfigService = new AppConfigService();
const authService = new AuthService();

export const SignInView = observer(() => {
const {
user: { fetchCurrentUser, fetchCurrentUserSettings },
appConfig: { envConfig },
} = useMobxStore();
// router
const router = useRouter();
Expand All @@ -38,12 +36,16 @@ export const SignInView = observer(() => {
const [isLoading, setLoading] = useState(false);
// toast
const { setToastAlert } = useToast();
// fetch app config
const { data, error: appConfigError } = useSWR("APP_CONFIG", () => appConfigService.envConfig());
// computed
const enableEmailPassword =
data &&
(data?.email_password_login || !(data?.email_password_login || data?.magic_login || data?.google || data?.github));
envConfig &&
(envConfig?.email_password_login ||
!(
envConfig?.email_password_login ||
envConfig?.magic_login ||
envConfig?.google_client_id ||
envConfig?.github_client_id
));

const handleLoginRedirection = useCallback(
(user: IUser) => {
Expand Down Expand Up @@ -114,11 +116,11 @@ export const SignInView = observer(() => {
const handleGitHubSignIn = async (credential: string) => {
try {
setLoading(true);
if (data && data.github && credential) {
if (envConfig && envConfig.github_client_id && credential) {
const socialAuthPayload = {
medium: "github",
credential,
clientId: data.github,
clientId: envConfig.github_client_id,
};
const response = await authService.socialAuth(socialAuthPayload);
if (response) {
Expand Down Expand Up @@ -195,7 +197,7 @@ export const SignInView = observer(() => {
Sign in to Plane
</h1>

{!data && !appConfigError ? (
{!envConfig ? (
<div className="pt-10 w-ful">
<Loader className="space-y-4 w-full pb-4">
<Loader.Item height="46px" width="360px" />
Expand All @@ -211,16 +213,20 @@ export const SignInView = observer(() => {
<>
<>
{enableEmailPassword && <EmailPasswordForm onSubmit={handlePasswordSignIn} />}
{data?.magic_login && (
{envConfig?.magic_login && (
<div className="flex flex-col divide-y divide-custom-border-200">
<div className="pb-7">
<EmailCodeForm handleSignIn={handleEmailCodeSignIn} />
</div>
</div>
)}
<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?.github && <GithubLoginButton clientId={data?.github} handleSignIn={handleGitHubSignIn} />}
{envConfig?.google_client_id && (
<GoogleLoginButton clientId={envConfig?.google_client_id} handleSignIn={handleGoogleSignIn} />
)}
{envConfig?.github_client_id && (
<GithubLoginButton clientId={envConfig?.github_client_id} handleSignIn={handleGitHubSignIn} />
)}
</div>
</>
<p className="pt-16 text-custom-text-200 text-sm text-center">
Expand Down
25 changes: 14 additions & 11 deletions web/hooks/use-integration-popup.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import { useRef, useState } from "react";

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 router = useRouter();
const { workspaceSlug, projectId } = router.query;

const providerUrls: { [key: string]: string } = {
github: `https://github.com/apps/${
process.env.NEXT_PUBLIC_GITHUB_APP_NAME
}/installations/new?state=${workspaceSlug?.toString()}`,
slack: `https://slack.com/oauth/v2/authorize?scope=chat:write,im:history,im:write,links:read,links:write,users:read,users:read.email&amp;user_scope=&amp;&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()}${
github: `https://github.com/apps/${github_app_name}/installations/new?state=${workspaceSlug?.toString()}`,
slack: `https://slack.com/oauth/v2/authorize?scope=chat:write,im:history,im:write,links:read,links:write,users:read,users:read.email&amp;user_scope=&amp;&client_id=${slack_client_id}&state=${workspaceSlug?.toString()}`,
slackChannel: `https://slack.com/oauth/v2/authorize?scope=incoming-webhook&client_id=${slack_client_id}&state=${workspaceSlug?.toString()},${projectId?.toString()}${
stateParams ? "," + stateParams : ""
}`,
};
Expand Down
Loading