refactor: import/export code (#735)

This commit is contained in:
Aaryan Khandelwal 2023-04-07 13:27:57 +05:30 committed by GitHub
parent c0b732f1f1
commit 35f9876981
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 163 additions and 192 deletions

View File

@ -0,0 +1,9 @@
export * from "./auth";
export * from "./import-configure";
export * from "./import-confirm";
export * from "./import-data";
export * from "./import-users";
export * from "./repo-details";
export * from "./root";
export * from "./select-repository";
export * from "./single-user-select";

View File

@ -1,14 +1,15 @@
import { FC, useState } from "react"; import React, { useState } from "react";
import Link from "next/link"; import Link from "next/link";
import Image from "next/image"; import Image from "next/image";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { mutate } from "swr"; import useSWR, { mutate } from "swr";
// react-hook-form // react-hook-form
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
// services // services
import IntegrationService from "services/integration";
import GithubIntegrationService from "services/integration/github.service"; import GithubIntegrationService from "services/integration/github.service";
// hooks // hooks
import useToast from "hooks/use-toast"; import useToast from "hooks/use-toast";
@ -24,22 +25,15 @@ import {
import { CogIcon, CloudUploadIcon, UsersIcon, CheckIcon } from "components/icons"; import { CogIcon, CloudUploadIcon, UsersIcon, CheckIcon } from "components/icons";
import { ArrowLeftIcon, ListBulletIcon } from "@heroicons/react/24/outline"; import { ArrowLeftIcon, ListBulletIcon } from "@heroicons/react/24/outline";
// images // images
import GithubLogo from "public/logos/github-square.png"; import GithubLogo from "public/services/github.png";
// types // types
import { import { IGithubRepoCollaborator, IGithubServiceImportFormData } from "types";
IAppIntegrations,
IGithubRepoCollaborator,
IGithubServiceImportFormData,
IWorkspaceIntegrations,
} from "types";
// fetch-keys // fetch-keys
import { IMPORTER_SERVICES_LIST } from "constants/fetch-keys"; import {
APP_INTEGRATIONS,
type Props = { IMPORTER_SERVICES_LIST,
provider: string | undefined; WORKSPACE_INTEGRATIONS,
appIntegrations: IAppIntegrations[] | undefined; } from "constants/fetch-keys";
workspaceIntegrations: IWorkspaceIntegrations[] | undefined;
};
export type TIntegrationSteps = export type TIntegrationSteps =
| "import-configure" | "import-configure"
@ -95,18 +89,14 @@ const integrationWorkflowData = [
}, },
]; ];
export const GithubIntegrationRoot: FC<Props> = ({ export const GithubImporterRoot = () => {
provider,
appIntegrations,
workspaceIntegrations,
}) => {
const [currentStep, setCurrentStep] = useState<IIntegrationData>({ const [currentStep, setCurrentStep] = useState<IIntegrationData>({
state: "import-configure", state: "import-configure",
}); });
const [users, setUsers] = useState<IUserDetails[]>([]); const [users, setUsers] = useState<IUserDetails[]>([]);
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug, provider } = router.query;
const { setToastAlert } = useToast(); const { setToastAlert } = useToast();
@ -114,6 +104,17 @@ export const GithubIntegrationRoot: FC<Props> = ({
defaultValues: defaultFormValues, defaultValues: defaultFormValues,
}); });
const { data: appIntegrations } = useSWR(APP_INTEGRATIONS, () =>
IntegrationService.getAppIntegrationsList()
);
const { data: workspaceIntegrations } = useSWR(
workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug as string) : null,
workspaceSlug
? () => IntegrationService.getWorkspaceIntegrationsList(workspaceSlug as string)
: null
);
const activeIntegrationState = () => { const activeIntegrationState = () => {
const currentElementIndex = integrationWorkflowData.findIndex( const currentElementIndex = integrationWorkflowData.findIndex(
(i) => i?.key === currentStep?.state (i) => i?.key === currentStep?.state
@ -189,9 +190,8 @@ export const GithubIntegrationRoot: FC<Props> = ({
</div> </div>
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
{integrationWorkflowData.map((integration, index) => ( {integrationWorkflowData.map((integration, index) => (
<> <React.Fragment key={integration.key}>
<div <div
key={integration.key}
className={`flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full border ${ className={`flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full border ${
index <= activeIntegrationState() index <= activeIntegrationState()
? `border-[#3F76FF] bg-[#3F76FF] text-white ${ ? `border-[#3F76FF] bg-[#3F76FF] text-white ${
@ -220,7 +220,7 @@ export const GithubIntegrationRoot: FC<Props> = ({
{" "} {" "}
</div> </div>
)} )}
</> </React.Fragment>
))} ))}
</div> </div>
</div> </div>
@ -230,7 +230,7 @@ export const GithubIntegrationRoot: FC<Props> = ({
{currentStep?.state === "import-configure" && ( {currentStep?.state === "import-configure" && (
<GithubImportConfigure <GithubImportConfigure
handleStepChange={handleStepChange} handleStepChange={handleStepChange}
provider={provider} provider={provider as string}
appIntegrations={appIntegrations} appIntegrations={appIntegrations}
workspaceIntegrations={workspaceIntegrations} workspaceIntegrations={workspaceIntegrations}
/> />

View File

@ -1,45 +1,44 @@
import { FC, useState } from "react"; import { useState } from "react";
import Link from "next/link"; import Link from "next/link";
import Image from "next/image"; import Image from "next/image";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { mutate } from "swr"; import useSWR, { mutate } from "swr";
// icons // services
import { ArrowRightIcon } from "components/icons"; import IntegrationService from "services/integration";
// components // components
import { DeleteImportModal, GithubIntegrationRoot, SingleImport } from "components/integration"; import {
// icons DeleteImportModal,
import { ArrowPathIcon } from "@heroicons/react/24/outline"; GithubImporterRoot,
JiraImporterRoot,
SingleImport,
} from "components/integration";
// ui // ui
import { Loader, PrimaryButton } from "components/ui"; import { Loader, PrimaryButton } from "components/ui";
// images // icons
import GithubLogo from "public/logos/github-square.png"; import { ArrowPathIcon } from "@heroicons/react/24/outline";
import { ArrowRightIcon } from "components/icons";
// types // types
import { IAppIntegrations, IImporterService, IWorkspaceIntegrations } from "types"; import { IImporterService } from "types";
// fetch-keys // fetch-keys
import { IMPORTER_SERVICES_LIST } from "constants/fetch-keys"; import { IMPORTER_SERVICES_LIST } from "constants/fetch-keys";
// constants
import { IMPORTERS_EXPORTERS_LIST } from "constants/workspace";
type Props = { const IntegrationGuide = () => {
provider: string | undefined;
appIntegrations: IAppIntegrations[] | undefined;
workspaceIntegrations: IWorkspaceIntegrations[] | undefined;
importerServices: IImporterService[] | undefined;
};
const IntegrationGuide: FC<Props> = ({
provider,
appIntegrations,
workspaceIntegrations,
importerServices,
}) => {
const [refreshing, setRefreshing] = useState(false); const [refreshing, setRefreshing] = useState(false);
const [deleteImportModal, setDeleteImportModal] = useState(false); const [deleteImportModal, setDeleteImportModal] = useState(false);
const [importToDelete, setImportToDelete] = useState<IImporterService | null>(null); const [importToDelete, setImportToDelete] = useState<IImporterService | null>(null);
const router = useRouter(); const router = useRouter();
const { workspaceSlug } = router.query; const { workspaceSlug, provider } = router.query;
const { data: importerServices } = useSWR(
workspaceSlug ? IMPORTER_SERVICES_LIST(workspaceSlug as string) : null,
workspaceSlug ? () => IntegrationService.getImporterServicesList(workspaceSlug as string) : null
);
const handleDeleteImport = (importService: IImporterService) => { const handleDeleteImport = (importService: IImporterService) => {
setImportToDelete(importService); setImportToDelete(importService);
@ -53,10 +52,10 @@ const IntegrationGuide: FC<Props> = ({
handleClose={() => setDeleteImportModal(false)} handleClose={() => setDeleteImportModal(false)}
data={importToDelete} data={importToDelete}
/> />
<div className="space-y-5"> <div className="space-y-2">
{!provider && ( {!provider && (
<> <>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2 mb-5">
<div className="h-full w-full space-y-1"> <div className="h-full w-full space-y-1">
<div className="text-lg font-medium">Relocation Guide</div> <div className="text-lg font-medium">Relocation Guide</div>
<div className="text-sm"> <div className="text-sm">
@ -64,109 +63,92 @@ const IntegrationGuide: FC<Props> = ({
services. This tool will guide you to relocate the issue to Plane. services. This tool will guide you to relocate the issue to Plane.
</div> </div>
</div> </div>
<div className="flex flex-shrink-0 cursor-pointer items-center gap-2 text-sm font-medium text-[#3F76FF] hover:text-opacity-80"> <a href="https://docs.plane.so" target="_blank" rel="noopener noreferrer">
<div>Read More</div> <div className="flex flex-shrink-0 cursor-pointer items-center gap-2 whitespace-nowrap text-sm font-medium text-[#3F76FF] hover:text-opacity-80">
<div> Read More
<ArrowRightIcon width={"18px"} color={"#3F76FF"} /> <ArrowRightIcon width={"18px"} color={"#3F76FF"} />
</div> </div>
</div> </a>
</div> </div>
<div> <div className="space-y-2">
{appIntegrations ? ( {IMPORTERS_EXPORTERS_LIST.map((service) => (
appIntegrations.length > 0 ? ( <div key={service.provider} className="rounded-[10px] border bg-white p-4">
appIntegrations.map((integration, index) => ( <div className="flex items-center gap-4 whitespace-nowrap">
<div key={index} className="rounded-[10px] border bg-white p-4"> <div className="relative h-10 w-10 flex-shrink-0">
<div className="flex items-center gap-4 whitespace-nowrap"> <Image
<div className="h-[40px] w-[40px] flex-shrink-0"> src={service.logo}
{integration?.provider === "github" && ( layout="fill"
<Image src={GithubLogo} alt="GithubLogo" /> objectFit="cover"
)} alt={`${service.title} Logo`}
</div> />
<div className="w-full space-y-1"> </div>
<div className="flex items-center gap-2 font-medium"> <div className="w-full">
<h3>{integration?.title}</h3> <h3>{service.title}</h3>
</div> <p className="text-sm text-gray-500">{service.description}</p>
<div className="text-sm text-gray-500"> </div>
Activate GitHub integrations on individual projects to sync with <div className="flex-shrink-0">
specific repositories. <Link
</div> href={`/${workspaceSlug}/settings/import-export?provider=${service.provider}`}
</div> >
<div className="flex-shrink-0"> <a>
<Link href={`/${workspaceSlug}/settings/import-export?provider=github`}> <PrimaryButton>
<PrimaryButton>Import Now</PrimaryButton> <span className="capitalize">{service.type}</span> now
</Link> </PrimaryButton>
</div> </a>
</div> </Link>
<h3 className="mt-6 mb-2 font-medium text-lg flex gap-2">
Previous Imports
<button
type="button"
className="flex-shrink-0 flex items-center gap-1 outline-none text-xs py-1 px-1.5 bg-gray-100 rounded"
onClick={() => {
setRefreshing(true);
mutate(IMPORTER_SERVICES_LIST(workspaceSlug as string)).then(() =>
setRefreshing(false)
);
}}
>
<ArrowPathIcon
className={`h-3 w-3 ${refreshing ? "animate-spin" : ""}`}
/>{" "}
{refreshing ? "Refreshing..." : "Refresh status"}
</button>
</h3>
{importerServices ? (
importerServices.length > 0 ? (
<div className="space-y-2">
<div className="divide-y">
{importerServices.map((service) => (
<SingleImport
key={service.id}
service={service}
refreshing={refreshing}
handleDelete={() => handleDeleteImport(service)}
/>
))}
</div>
</div>
) : (
<div className="py-2 text-sm text-gray-800">
No previous imports available.
</div>
)
) : (
<Loader className="grid grid-cols-1 gap-3 mt-6">
<Loader.Item height="40px" width="100%" />
<Loader.Item height="40px" width="100%" />
<Loader.Item height="40px" width="100%" />
<Loader.Item height="40px" width="100%" />
</Loader>
)}
</div> </div>
))
) : (
<div className="py-5 text-center text-sm text-gray-800">
Integrations not available.
</div> </div>
</div>
))}
</div>
<div className="rounded-[10px] border bg-white p-4">
<h3 className="mb-2 font-medium text-lg flex gap-2">
Previous Imports
<button
type="button"
className="flex-shrink-0 flex items-center gap-1 outline-none text-xs py-1 px-1.5 bg-gray-100 rounded"
onClick={() => {
setRefreshing(true);
mutate(IMPORTER_SERVICES_LIST(workspaceSlug as string)).then(() =>
setRefreshing(false)
);
}}
>
<ArrowPathIcon className={`h-3 w-3 ${refreshing ? "animate-spin" : ""}`} />{" "}
{refreshing ? "Refreshing..." : "Refresh status"}
</button>
</h3>
{importerServices ? (
importerServices.length > 0 ? (
<div className="space-y-2">
<div className="divide-y">
{importerServices.map((service) => (
<SingleImport
key={service.id}
service={service}
refreshing={refreshing}
handleDelete={() => handleDeleteImport(service)}
/>
))}
</div>
</div>
) : (
<div className="py-2 text-sm text-gray-800">No previous imports available.</div>
) )
) : ( ) : (
<Loader className="grid grid-cols-1 gap-3"> <Loader className="grid grid-cols-1 gap-3 mt-6">
<Loader.Item height="34px" width="100%" /> <Loader.Item height="40px" width="100%" />
<Loader.Item height="34px" width="100%" /> <Loader.Item height="40px" width="100%" />
<Loader.Item height="40px" width="100%" />
<Loader.Item height="40px" width="100%" />
</Loader> </Loader>
)} )}
</div> </div>
</> </>
)} )}
{provider && provider === "github" && ( {provider && provider === "github" && <GithubImporterRoot />}
<GithubIntegrationRoot {provider && provider === "jira" && <JiraImporterRoot />}
provider={provider}
appIntegrations={appIntegrations}
workspaceIntegrations={workspaceIntegrations}
/>
)}
</div> </div>
</> </>
); );

View File

@ -3,16 +3,8 @@ export * from "./delete-import-modal";
export * from "./guide"; export * from "./guide";
export * from "./single-import"; export * from "./single-import";
// github integration // github
// authenticate export * from "./github";
export * from "./github/auth";
// layout // jira
export * from "./github/root"; export * from "./jira";
// components
export * from "./github/import-configure";
export * from "./github/import-data";
export * from "./github/repo-details";
export * from "./github/import-users";
export * from "./github/import-confirm";
export * from "./github/select-repository";
export * from "./github/single-user-select";

View File

@ -0,0 +1 @@
export * from "./root";

View File

@ -0,0 +1 @@
export const JiraImporterRoot = () => <></>;

View File

@ -1,8 +1,12 @@
// onboarding images
import Welcome from "public/onboarding/welcome.svg"; import Welcome from "public/onboarding/welcome.svg";
import Issue from "public/onboarding/issue.svg"; import Issue from "public/onboarding/issue.svg";
import Cycle from "public/onboarding/cycle.svg"; import Cycle from "public/onboarding/cycle.svg";
import Module from "public/onboarding/module.svg"; import Module from "public/onboarding/module.svg";
import CommandMenu from "public/onboarding/command-menu.svg"; import CommandMenu from "public/onboarding/command-menu.svg";
// services images
import GithubLogo from "public/services/github.png";
import JiraLogo from "public/services/jira.png";
export const ROLE = { export const ROLE = {
5: "Guest", 5: "Guest",
@ -62,3 +66,20 @@ export const ONBOARDING_CARDS = {
description: "With Command Menu, you can create, update and navigate across the platform.", description: "With Command Menu, you can create, update and navigate across the platform.",
}, },
}; };
export const IMPORTERS_EXPORTERS_LIST = [
{
provider: "github",
type: "import",
title: "GitHub",
description: "Import issues from GitHub repositories and sync them.",
logo: GithubLogo,
},
{
provider: "jira",
type: "import",
title: "Jira",
description: "Import issues and epics from Jira projects and epics.",
logo: JiraLogo,
},
];

View File

@ -1,13 +1,7 @@
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import useSWR from "swr";
// lib // lib
import { requiredWorkspaceAdmin } from "lib/auth"; import { requiredWorkspaceAdmin } from "lib/auth";
// services
import IntegrationService from "services/integration";
// hooks
import useToast from "hooks/use-toast";
// layouts // layouts
import AppLayout from "layouts/app-layout"; import AppLayout from "layouts/app-layout";
import IntegrationGuide from "components/integration/guide"; import IntegrationGuide from "components/integration/guide";
@ -16,34 +10,10 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// types // types
import { UserAuth } from "types"; import { UserAuth } from "types";
import type { GetServerSideProps, NextPage } from "next"; import type { GetServerSideProps, NextPage } from "next";
// fetch-keys
import {
APP_INTEGRATIONS,
IMPORTER_SERVICES_LIST,
WORKSPACE_INTEGRATIONS,
} from "constants/fetch-keys";
const ImportExport: NextPage<UserAuth> = (props) => { const ImportExport: NextPage<UserAuth> = (props) => {
const { setToastAlert } = useToast();
const router = useRouter(); const router = useRouter();
const { workspaceSlug, provider } = router.query; const { workspaceSlug } = router.query;
const { data: appIntegrations } = useSWR(APP_INTEGRATIONS, () =>
IntegrationService.getAppIntegrationsList()
);
const { data: workspaceIntegrations } = useSWR(
workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug as string) : null,
workspaceSlug
? () => IntegrationService.getWorkspaceIntegrationsList(workspaceSlug as string)
: null
);
const { data: importerServices } = useSWR(
workspaceSlug ? IMPORTER_SERVICES_LIST(workspaceSlug as string) : null,
workspaceSlug ? () => IntegrationService.getImporterServicesList(workspaceSlug as string) : null
);
return ( return (
<AppLayout <AppLayout
@ -56,12 +26,7 @@ const ImportExport: NextPage<UserAuth> = (props) => {
} }
settingsLayout settingsLayout
> >
<IntegrationGuide <IntegrationGuide />
provider={provider as string}
appIntegrations={appIntegrations}
workspaceIntegrations={workspaceIntegrations}
importerServices={importerServices}
/>
</AppLayout> </AppLayout>
); );
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB