forked from github/plane
refactor: import/export code (#735)
This commit is contained in:
parent
c0b732f1f1
commit
35f9876981
9
apps/app/components/integration/github/index.ts
Normal file
9
apps/app/components/integration/github/index.ts
Normal 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";
|
@ -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}
|
||||
/>
|
||||
|
@ -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>
|
||||
</>
|
||||
);
|
||||
|
@ -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";
|
||||
|
1
apps/app/components/integration/jira/index.ts
Normal file
1
apps/app/components/integration/jira/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./root";
|
1
apps/app/components/integration/jira/root.tsx
Normal file
1
apps/app/components/integration/jira/root.tsx
Normal file
@ -0,0 +1 @@
|
||||
export const JiraImporterRoot = () => <></>;
|
@ -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,
|
||||
},
|
||||
];
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
BIN
apps/app/public/services/github.png
Normal file
BIN
apps/app/public/services/github.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
apps/app/public/services/jira.png
Normal file
BIN
apps/app/public/services/jira.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 226 KiB |
Loading…
Reference in New Issue
Block a user