mirror of
https://github.com/makeplane/plane.git
synced 2026-07-13 22:09:12 +02:00
[SILO] - add pat token error handling in importer form (#2485)
* add pat token error handling in importer form * remove console logs
This commit is contained in:
@@ -689,7 +689,8 @@
|
||||
"add_seat_msg_free_trial": "You're trying to import {additionalUserCount} non-registered users and you've only {currentWorkspaceSubscriptionAvailableSeats} seats available in current plan. To continue importing upgrade now.",
|
||||
"add_seat_msg_paid": "You're trying to import {additionalUserCount} non-registered users and you've only {currentWorkspaceSubscriptionAvailableSeats} seats available in current plan. To continue importing buy atleast {extraSeatRequired} extra seats.",
|
||||
"skip_user_import_title": "Skip importing User data",
|
||||
"skip_user_import_description": "Skipping user import will result in work items, comments, and other data from {serviceName} being created by the user performing the migration in Plane. You can still manually add users later."
|
||||
"skip_user_import_description": "Skipping user import will result in work items, comments, and other data from {serviceName} being created by the user performing the migration in Plane. You can still manually add users later.",
|
||||
"invalid_pat": "Invalid Personal Access Token"
|
||||
},
|
||||
|
||||
"integrations": {
|
||||
|
||||
@@ -696,7 +696,8 @@
|
||||
"add_seat_msg_free_trial": "Estás intentando importar {additionalUserCount} usuarios no registrados y solo tienes {currentWorkspaceSubscriptionAvailableSeats} asientos disponibles en el plan actual. Para continuar importando, actualiza ahora.",
|
||||
"add_seat_msg_paid": "Estás intentando importar {additionalUserCount} usuarios no registrados y solo tienes {currentWorkspaceSubscriptionAvailableSeats} asientos disponibles en el plan actual. Para continuar importando, compra al menos {extraSeatRequired} asientos adicionales.",
|
||||
"skip_user_import_title": "Omitir importación de datos de usuario",
|
||||
"skip_user_import_description": "Omitir la importación de usuarios resultará en que los elementos de trabajo, comentarios y otros datos de {serviceName} sean creados por el usuario que realiza la migración en Plane. Aún puedes agregar usuarios manualmente más tarde."
|
||||
"skip_user_import_description": "Omitir la importación de usuarios resultará en que los elementos de trabajo, comentarios y otros datos de {serviceName} sean creados por el usuario que realiza la migración en Plane. Aún puedes agregar usuarios manualmente más tarde.",
|
||||
"invalid_pat": "Token de acceso personal inválido"
|
||||
},
|
||||
|
||||
"integrations": {
|
||||
|
||||
@@ -696,7 +696,8 @@
|
||||
"add_seat_msg_free_trial": "Vous essayez d'importer {additionalUserCount} utilisateurs non enregistrés et vous n'avez que {currentWorkspaceSubscriptionAvailableSeats} sièges disponibles dans le plan actuel. Pour continuer l'importation, passez à la version supérieure maintenant.",
|
||||
"add_seat_msg_paid": "Vous essayez d'importer {additionalUserCount} utilisateurs non enregistrés et vous n'avez que {currentWorkspaceSubscriptionAvailableSeats} sièges disponibles dans le plan actuel. Pour continuer l'importation, achetez au moins {extraSeatRequired} sièges supplémentaires.",
|
||||
"skip_user_import_title": "Ignorer l'importation des données utilisateur",
|
||||
"skip_user_import_description": "Ignorer l'importation des utilisateurs entraînera la création des éléments de travail, commentaires et autres données de {serviceName} par l'utilisateur effectuant la migration dans Plane. Vous pourrez toujours ajouter manuellement des utilisateurs plus tard."
|
||||
"skip_user_import_description": "Ignorer l'importation des utilisateurs entraînera la création des éléments de travail, commentaires et autres données de {serviceName} par l'utilisateur effectuant la migration dans Plane. Vous pourrez toujours ajouter manuellement des utilisateurs plus tard.",
|
||||
"invalid_pat": "Token de connexion personnel invalide"
|
||||
},
|
||||
|
||||
"integrations": {
|
||||
|
||||
@@ -696,7 +696,8 @@
|
||||
"add_seat_msg_free_trial": "未登録の{additionalUserCount}人のユーザーをインポートしようとしていますが、現在のプランでは{currentWorkspaceSubscriptionAvailableSeats}席しか利用できません。インポートを続けるにはアップグレードしてください。",
|
||||
"add_seat_msg_paid": "未登録の{additionalUserCount}人のユーザーをインポートしようとしていますが、現在のプランでは{currentWorkspaceSubscriptionAvailableSeats}席しか利用できません。インポートを続けるには少なくとも{extraSeatRequired}席追加購入してください。",
|
||||
"skip_user_import_title": "ユーザーデータのインポートをスキップ",
|
||||
"skip_user_import_description": "ユーザーのインポートをスキップすると、{serviceName}からの作業項目、コメント、その他のデータはPlaneで移行を実行しているユーザーによって作成されます。後でユーザーを手動で追加することもできます。"
|
||||
"skip_user_import_description": "ユーザーのインポートをスキップすると、{serviceName}からの作業項目、コメント、その他のデータはPlaneで移行を実行しているユーザーによって作成されます。後でユーザーを手動で追加することもできます。",
|
||||
"invalid_pat": "無効な個人アクセストークン"
|
||||
},
|
||||
|
||||
"integrations": {
|
||||
|
||||
@@ -696,7 +696,8 @@
|
||||
"add_seat_msg_free_trial": "您正在尝试导入 {additionalUserCount} 个未注册用户,但当前计划中只有 {currentWorkspaceSubscriptionAvailableSeats} 个席位可用。要继续导入,请立即升级。",
|
||||
"add_seat_msg_paid": "您正在尝试导入 {additionalUserCount} 个未注册用户,但当前计划中只有 {currentWorkspaceSubscriptionAvailableSeats} 个席位可用。要继续导入,请至少购买 {extraSeatRequired} 个额外席位。",
|
||||
"skip_user_import_title": "跳过导入用户数据",
|
||||
"skip_user_import_description": "跳过用户导入将导致工作项、评论和来自 {serviceName} 的其他数据由在 Plane 中执行迁移的用户创建。您以后仍可以手动添加用户。"
|
||||
"skip_user_import_description": "跳过用户导入将导致工作项、评论和来自 {serviceName} 的其他数据由在 Plane 中执行迁移的用户创建。您以后仍可以手动添加用户。",
|
||||
"invalid_pat": "无效的个人访问令牌"
|
||||
},
|
||||
|
||||
"integrations": {
|
||||
|
||||
@@ -10,6 +10,8 @@ import { AuthFormInput, TAuthFormInputFormField } from "@/plane-web/silo/ui/auth
|
||||
// plane web types
|
||||
import { TAsanaPATFormFields } from "@/plane-web/types/importers/asana";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { TImporterPATError } from "@/plane-web/types";
|
||||
import ErrorBanner from "../../ui/error-banner";
|
||||
|
||||
export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
// hooks
|
||||
@@ -22,6 +24,18 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
const [formData, setFormData] = useState<TAsanaPATFormFields>({
|
||||
personalAccessToken: "",
|
||||
});
|
||||
const [patError, setPatError] = useState<TImporterPATError>({
|
||||
showPATError: false,
|
||||
message: "",
|
||||
});
|
||||
|
||||
const togglePATError = (flag: boolean) => {
|
||||
setPatError((prev) => ({ ...prev, showPATError: flag }));
|
||||
};
|
||||
|
||||
const updatePATError = (message: string) => {
|
||||
setPatError((prev) => ({ ...prev, message }));
|
||||
};
|
||||
|
||||
// handlers
|
||||
const handleFormData = <T extends keyof TAsanaPATFormFields>(key: T, value: TAsanaPATFormFields[T]) => {
|
||||
@@ -38,11 +52,9 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
setIsLoading(true);
|
||||
await authWithPAT(formData);
|
||||
} catch (error: any) {
|
||||
setToast({
|
||||
type: TOAST_TYPE.ERROR,
|
||||
title: "Error!",
|
||||
message: error?.message?.toString() || "Something went wrong while authorizing Asana",
|
||||
});
|
||||
const { message } = error as { message: string };
|
||||
updatePATError(message || "Something went wrong while authorizing Jira");
|
||||
togglePATError(true);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -84,6 +96,11 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
{
|
||||
patError.showPATError && (
|
||||
<ErrorBanner message={t("importers.invalid_pat")} onClose={() => { togglePATError(false) }} />
|
||||
)
|
||||
}
|
||||
<div className="grid grid-cols-1 gap-x-12 gap-y-8 w-full">
|
||||
{asanaPatFormFields.map((field) => (
|
||||
<AuthFormInput
|
||||
|
||||
@@ -12,6 +12,8 @@ import { useJiraServerImporter } from "@/plane-web/hooks/store";
|
||||
// plane web types
|
||||
import { TJiraPATFormFields } from "@/plane-web/types/importers/jira-server";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { TImporterPATError } from "@/plane-web/types";
|
||||
import ErrorBanner from "../../ui/error-banner";
|
||||
|
||||
export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
// hooks
|
||||
@@ -28,6 +30,19 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
hostname: "",
|
||||
});
|
||||
|
||||
const [patError, setPatError] = useState<TImporterPATError>({
|
||||
showPATError: false,
|
||||
message: "",
|
||||
});
|
||||
|
||||
const togglePATError = (flag: boolean) => {
|
||||
setPatError((prev) => ({ ...prev, showPATError: flag }));
|
||||
};
|
||||
|
||||
const updatePATError = (message: string) => {
|
||||
setPatError((prev) => ({ ...prev, message }));
|
||||
};
|
||||
|
||||
// handlers
|
||||
const handleFormData = <T extends keyof TJiraPATFormFields>(key: T, value: TJiraPATFormFields[T]) => {
|
||||
setFormData((prev) => ({ ...prev, [key]: value }));
|
||||
@@ -47,11 +62,9 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
formData.hostname = stripTrailingSlash(formData.hostname);
|
||||
await authWithPAT(formData);
|
||||
} catch (error) {
|
||||
setToast({
|
||||
type: TOAST_TYPE.ERROR,
|
||||
title: "Error!",
|
||||
message: error?.toString() || "Something went wrong while authorizing Jira",
|
||||
});
|
||||
const { message } = error as { message: string };
|
||||
updatePATError(message || "Something went wrong while authorizing Jira");
|
||||
togglePATError(true);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -113,6 +126,11 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
{
|
||||
patError.showPATError && (
|
||||
<ErrorBanner message={t("importers.invalid_pat")} onClose={() => { togglePATError(false) }} />
|
||||
)
|
||||
}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-12 gap-y-8 w-full">
|
||||
{jiraPatFormFields.map((field) => (
|
||||
<AuthFormInput
|
||||
|
||||
@@ -4,14 +4,15 @@ import { FC, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
// plane imports
|
||||
import { stripTrailingSlash } from "@plane/etl/core";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button, setToast, TOAST_TYPE } from "@plane/ui";
|
||||
// plane web hooks
|
||||
import { useJiraImporter } from "@/plane-web/hooks/store";
|
||||
// plane web components
|
||||
import { AuthFormInput, TAuthFormInputFormField } from "@/plane-web/silo/ui/auth-form-input";
|
||||
// plane web types
|
||||
import { TJiraPATFormFields } from "@/plane-web/types";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { TImporterPATError, TJiraPATFormFields } from "@/plane-web/types";
|
||||
import ErrorBanner from "../../ui/error-banner";
|
||||
|
||||
export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
// hooks
|
||||
@@ -19,7 +20,7 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
auth: { authWithPAT },
|
||||
} = useJiraImporter();
|
||||
|
||||
const {t} = useTranslation();
|
||||
const { t } = useTranslation();
|
||||
// states
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [formData, setFormData] = useState<TJiraPATFormFields>({
|
||||
@@ -27,6 +28,18 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
userEmail: "",
|
||||
hostname: "",
|
||||
});
|
||||
const [patError, setPatError] = useState<TImporterPATError>({
|
||||
showPATError: false,
|
||||
message: "",
|
||||
});
|
||||
|
||||
const togglePATError = (flag: boolean) => {
|
||||
setPatError((prev) => ({ ...prev, showPATError: flag }));
|
||||
};
|
||||
|
||||
const updatePATError = (message: string) => {
|
||||
setPatError((prev) => ({ ...prev, message }));
|
||||
};
|
||||
|
||||
// handlers
|
||||
const handleFormData = <T extends keyof TJiraPATFormFields>(key: T, value: TJiraPATFormFields[T]) => {
|
||||
@@ -47,11 +60,9 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
formData.hostname = stripTrailingSlash(formData.hostname);
|
||||
await authWithPAT(formData);
|
||||
} catch (error) {
|
||||
setToast({
|
||||
type: TOAST_TYPE.ERROR,
|
||||
title: "Error!",
|
||||
message: error?.toString() || "Something went wrong while authorizing Jira",
|
||||
});
|
||||
const { message } = error as { message: string };
|
||||
updatePATError(message || "Something went wrong while authorizing Jira");
|
||||
togglePATError(true);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -75,7 +86,7 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
className="text-custom-primary-100 hover:underline"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{" "} {t("jira_importer.atlassian_security_settings")}
|
||||
{" "} {t("jira_importer.atlassian_security_settings")}
|
||||
</a>
|
||||
</>
|
||||
),
|
||||
@@ -109,10 +120,15 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
<div className="relative flex flex-col border-b border-custom-border-100 pb-3.5">
|
||||
<h3 className="text-xl font-medium">Jira to Plane {t("importers.migration_assistant")}</h3>
|
||||
<p className="text-custom-text-300 text-sm">
|
||||
{t("importers.migration_assistant_description", { "serviceName": "Jira" })}
|
||||
{t("importers.migration_assistant_description", { "serviceName": "Jira" })}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
{
|
||||
patError.showPATError && (
|
||||
<ErrorBanner message={t("importers.invalid_pat")} onClose={() => { togglePATError(false) }} />
|
||||
)
|
||||
}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-12 gap-y-8 w-full">
|
||||
{jiraPatFormFields.map((field) => (
|
||||
<AuthFormInput
|
||||
|
||||
@@ -10,6 +10,8 @@ import { AuthFormInput, TAuthFormInputFormField } from "@/plane-web/silo/ui/auth
|
||||
// plane web types
|
||||
import { TLinearPATFormFields } from "@/plane-web/types/importers/linear";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { TImporterPATError } from "@/plane-web/types";
|
||||
import ErrorBanner from "../../ui/error-banner";
|
||||
|
||||
export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
// hooks
|
||||
@@ -24,6 +26,19 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
personalAccessToken: "",
|
||||
});
|
||||
|
||||
const [patError, setPatError] = useState<TImporterPATError>({
|
||||
showPATError: false,
|
||||
message: "",
|
||||
});
|
||||
|
||||
const togglePATError = (flag: boolean) => {
|
||||
setPatError((prev) => ({ ...prev, showPATError: flag }));
|
||||
};
|
||||
|
||||
const updatePATError = (message: string) => {
|
||||
setPatError((prev) => ({ ...prev, message }));
|
||||
};
|
||||
|
||||
// handlers
|
||||
const handleFormData = <T extends keyof TLinearPATFormFields>(key: T, value: TLinearPATFormFields[T]) => {
|
||||
setFormData((prev) => ({ ...prev, [key]: value }));
|
||||
@@ -40,11 +55,9 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
setIsLoading(true);
|
||||
await authWithPAT(formData);
|
||||
} catch (error) {
|
||||
setToast({
|
||||
type: TOAST_TYPE.ERROR,
|
||||
title: "Error!",
|
||||
message: error?.toString() || "Something went wrong while authorizing Linear",
|
||||
});
|
||||
const { message } = error as { message: string };
|
||||
updatePATError(message || "Something went wrong while authorizing Jira");
|
||||
togglePATError(true);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
@@ -86,6 +99,11 @@ export const PersonalAccessTokenAuth: FC = observer(() => {
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-6">
|
||||
{
|
||||
patError.showPATError && (
|
||||
<ErrorBanner message={t("importers.invalid_pat")} onClose={() => { togglePATError(false) }} />
|
||||
)
|
||||
}
|
||||
{linearPatFormFields.map((field) => (
|
||||
<AuthFormInput
|
||||
key={field.key}
|
||||
|
||||
17
web/ee/components/importers/ui/error-banner.tsx
Normal file
17
web/ee/components/importers/ui/error-banner.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
"use client"
|
||||
|
||||
import React from "react"
|
||||
import { X } from "lucide-react"
|
||||
import { Button } from "@plane/ui"
|
||||
|
||||
|
||||
export default function ErrorBanner({ message, onClose }: { message: string, onClose: () => void }) {
|
||||
return (<div className="flex items-center justify-between gap-2 text-red-50 bg-red-500/20 rounded-md p-2">
|
||||
<span className="text-sm">
|
||||
{message}
|
||||
</span>
|
||||
<Button variant="link-neutral" size="sm" onClick={onClose}>
|
||||
<X size={14} color="white" />
|
||||
</Button>
|
||||
</div>)
|
||||
}
|
||||
@@ -2,3 +2,4 @@ export * from "./stepper";
|
||||
export * from "./dropdown";
|
||||
export * from "./add-seats-alert-banner"
|
||||
export * from "./skip-user-import-toggle"
|
||||
export * from "./error-banner"
|
||||
@@ -18,3 +18,9 @@ export type TPlanePriorityData = {
|
||||
key: TPlanePriority;
|
||||
label: string;
|
||||
};
|
||||
|
||||
|
||||
export type TImporterPATError = {
|
||||
showPATError: boolean;
|
||||
message: string;
|
||||
}
|
||||
Reference in New Issue
Block a user