[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:
Saurabh Kumar
2025-02-13 15:19:37 +05:30
committed by GitHub
parent 2b7373f55a
commit 1a57d3e038
12 changed files with 128 additions and 30 deletions

View File

@@ -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": {

View File

@@ -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": {

View File

@@ -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": {

View File

@@ -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": {

View File

@@ -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": {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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}

View 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>)
}

View File

@@ -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"

View File

@@ -18,3 +18,9 @@ export type TPlanePriorityData = {
key: TPlanePriority;
label: string;
};
export type TImporterPATError = {
showPATError: boolean;
message: string;
}