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

View File

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

View File

@ -3,16 +3,8 @@ export * from "./delete-import-modal";
export * from "./guide";
export * from "./single-import";
// github integration
// authenticate
export * from "./github/auth";
// layout
export * from "./github/root";
// 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";
// github
export * from "./github";
// jira
export * from "./jira";

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 Issue from "public/onboarding/issue.svg";
import Cycle from "public/onboarding/cycle.svg";
import Module from "public/onboarding/module.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 = {
5: "Guest",
@ -62,3 +66,20 @@ export const ONBOARDING_CARDS = {
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 useSWR from "swr";
// lib
import { requiredWorkspaceAdmin } from "lib/auth";
// services
import IntegrationService from "services/integration";
// hooks
import useToast from "hooks/use-toast";
// layouts
import AppLayout from "layouts/app-layout";
import IntegrationGuide from "components/integration/guide";
@ -16,34 +10,10 @@ import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs";
// types
import { UserAuth } from "types";
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 { setToastAlert } = useToast();
const router = useRouter();
const { workspaceSlug, provider } = 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
);
const { workspaceSlug } = router.query;
return (
<AppLayout
@ -56,12 +26,7 @@ const ImportExport: NextPage<UserAuth> = (props) => {
}
settingsLayout
>
<IntegrationGuide
provider={provider as string}
appIntegrations={appIntegrations}
workspaceIntegrations={workspaceIntegrations}
importerServices={importerServices}
/>
<IntegrationGuide />
</AppLayout>
);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB