diff --git a/apps/web/components/import-feed/History.tsx b/apps/web/components/import-feed/History.tsx index ca152ae4b..d4a912ad6 100644 --- a/apps/web/components/import-feed/History.tsx +++ b/apps/web/components/import-feed/History.tsx @@ -97,6 +97,7 @@ export function History() { return item.originalFileName ? ( downloadOriginalFile([item._id, item.originalFileName])} > diff --git a/apps/web/components/imports/schema/ColumnsTable.tsx b/apps/web/components/imports/schema/ColumnsTable.tsx index 1d3f0c9cc..be12d5108 100644 --- a/apps/web/components/imports/schema/ColumnsTable.tsx +++ b/apps/web/components/imports/schema/ColumnsTable.tsx @@ -1,9 +1,20 @@ -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useState } from 'react'; import { Controller } from 'react-hook-form'; -import { ActionIcon, Flex, Tooltip, TextInput as Input, Group, Badge, SelectItem } from '@mantine/core'; +import { + ActionIcon, + Flex, + Tooltip, + TextInput as Input, + Group, + Badge, + SelectItem, + Text, + useMantineTheme, + LoadingOverlay, +} from '@mantine/core'; +import { colors as appColors } from '@config'; import { useSchema } from '@hooks/useSchema'; -import { colors } from '@config'; import { ColumnTypesEnum, IColumn } from '@impler/shared'; import { Button } from '@ui/button'; @@ -23,7 +34,7 @@ interface ColumnsTableProps { } export function ColumnsTable({ templateId }: ColumnsTableProps) { - const ValidationRef = useRef(false); + const { colors: themeColors } = useMantineTheme(); const { getColumnTypes } = useSchema({ templateId }); const [columnTypes, setColumnType] = useState(getColumnTypes()); @@ -33,10 +44,12 @@ export function ColumnsTable({ templateId }: ColumnsTableProps) { register, getValues, showAddRow, - handleSubmit, onMoveColumns, + validationRef, setShowAddRow, + onCancelAddColumn, onEditColumnClick, + onAddColumnSubmit, onValidationsClick, onDeleteColumnClick, isColumnCreateLoading, @@ -45,6 +58,7 @@ export function ColumnsTable({ templateId }: ColumnsTableProps) { }); const onValidationsButtonClick = () => { + validationRef.current = true; const values = getValues(); onValidationsClick({ ...values, key: values.key || values.name }); }; @@ -54,16 +68,9 @@ export function ColumnsTable({ templateId }: ColumnsTableProps) { }, []); return ( -
{ - handleSubmit(); - e.preventDefault(); - ValidationRef.current = false; - }} - id="columns" - > + - emptyDataText='No columns found click on "+" to add new column' + emptyDataText='No columns found click on "+" to add a new column' headings={[ { title: 'Name', @@ -79,7 +86,7 @@ export function ColumnsTable({ templateId }: ColumnsTableProps) { title: 'Frozen?', key: 'isFrozen', width: '10%', - Cell: (item) => item.isFrozen && , + Cell: (item) => item.isFrozen && , }, { title: 'Validations', @@ -107,12 +114,12 @@ export function ColumnsTable({ templateId }: ColumnsTableProps) { Cell: (item) => ( onEditColumnClick(item._id)}> - + onDeleteColumnClick(item._id)}> - + - + ), width: '15%', @@ -122,54 +129,66 @@ export function ColumnsTable({ templateId }: ColumnsTableProps) { {showAddRow ? ( <> - - - - ( - - )} - /> - - - - - + + + + + + ( + + )} + /> + + + - - - setShowAddRow(false)}> - + + + * Press{' '} + + ENTER + {' '} + to save,{' '} + + ESC + {' '} + to cancel or click on{' '} + + VALIDATIONS + {' '} + to configure column behavior + ) : ( setShowAddRow(true)} > - + diff --git a/apps/web/components/imports/schema/Schema.tsx b/apps/web/components/imports/schema/Schema.tsx index 32d7e8368..317cce08c 100644 --- a/apps/web/components/imports/schema/Schema.tsx +++ b/apps/web/components/imports/schema/Schema.tsx @@ -19,7 +19,7 @@ export function Schema({ templateId }: SchemaProps) { - setShowJsonEditor(!showJsonEditor)}> + setShowJsonEditor(!showJsonEditor)}> diff --git a/apps/web/components/settings/GenerateAccessToken.tsx b/apps/web/components/settings/GenerateAccessToken.tsx index 7c9d1b8aa..55a8ec63d 100644 --- a/apps/web/components/settings/GenerateAccessToken.tsx +++ b/apps/web/components/settings/GenerateAccessToken.tsx @@ -19,7 +19,7 @@ export function GenerateAccessToken() { value={accessToken} rightSection={ - clipboardApiKey.copy(accessToken)}> + clipboardApiKey.copy(accessToken)}> {clipboardApiKey.copied ? : } diff --git a/apps/web/hooks/useKeyboardEvent.tsx b/apps/web/hooks/useKeyboardEvent.tsx new file mode 100644 index 000000000..fc9096420 --- /dev/null +++ b/apps/web/hooks/useKeyboardEvent.tsx @@ -0,0 +1,30 @@ +import { useEffect, useRef } from 'react'; + +export function useKeyboardEvent(key: string, callback: () => void) { + const listenerRef = useRef(null); + + useEffect(() => { + if (listenerRef.current) return; // Skip if listener is already set + + const handleKeyDown = (e: globalThis.KeyboardEvent) => { + if (e.key === key) callback(); + }; + + document.body.addEventListener('keydown', handleKeyDown, { + capture: false, + }); + + // Store the listener reference + listenerRef.current = handleKeyDown; + + // Cleanup function + return () => { + if (listenerRef.current) { + document.body.removeEventListener('keydown', listenerRef.current, { + capture: false, + }); + listenerRef.current = null; + } + }; + }, [callback, key]); +} diff --git a/apps/web/hooks/useSchema.tsx b/apps/web/hooks/useSchema.tsx index b3ea94863..17faf4dd0 100644 --- a/apps/web/hooks/useSchema.tsx +++ b/apps/web/hooks/useSchema.tsx @@ -1,10 +1,9 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import dynamic from 'next/dynamic'; - import { modals } from '@mantine/modals'; import { useForm } from 'react-hook-form'; -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { SelectItem } from '@mantine/core'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { commonApi } from '@libs/api'; import { notify } from '@libs/notify'; @@ -12,9 +11,11 @@ import { track } from '@libs/amplitude'; import { IColumn, IErrorObject } from '@impler/shared'; import { API_KEYS, COLUMN_TYPES, MODAL_KEYS, MODAL_TITLES, NOTIFICATION_KEYS } from '@config'; +import { useKeyboardEvent } from './useKeyboardEvent'; import { useUpdateBulkColumns } from './useUpdateBulkColumns'; -import { ConfirmDelete } from '@components/imports/forms/ConfirmDelete'; import { usePlanMetaData } from 'store/planmeta.store.context'; +import { ConfirmDelete } from '@components/imports/forms/ConfirmDelete'; + const ColumnForm = dynamic(() => import('@components/imports/forms/ColumnForm').then((mod) => mod.ColumnForm), { ssr: false, }); @@ -27,6 +28,7 @@ export function useSchema({ templateId }: UseSchemaProps) { const { meta } = usePlanMetaData(); const queryClient = useQueryClient(); const [showAddRow, setShowAddRow] = useState(false); + const validationRef = useRef(undefined); const { register, control, watch, reset, setFocus, handleSubmit, formState, getValues } = useForm({ defaultValues: { type: 'String', @@ -125,7 +127,11 @@ export function useSchema({ templateId }: UseSchemaProps) { }); } } - + const onAddColumnSubmit = handleSubmit((data) => { + validationRef.current = false; + if (!data.key) data.key = data.name; + createColumn(data); + }); function onValidationsClick(columnData: Partial) { if (columnData) { modals.open({ @@ -138,6 +144,7 @@ export function useSchema({ templateId }: UseSchemaProps) { data={columnData} onSubmit={(data) => { reset(data); + onAddColumnSubmit(); modals.close(MODAL_KEYS.COLUMN_UPDATE); }} /> @@ -165,11 +172,10 @@ export function useSchema({ templateId }: UseSchemaProps) { children: onConfirmDelete(columnId)} />, }); } - function onAddColumnSubmit(data: IColumn) { - if (!data.key) data.key = data.name; - createColumn(data); + function onCancelAddColumn() { + setShowAddRow(false); + validationRef.current = false; } - function getColumnTypes(): SelectItem[] { if (!meta) return COLUMN_TYPES; @@ -186,6 +192,11 @@ export function useSchema({ templateId }: UseSchemaProps) { if (showAddRow) setFocus('name'); }, [setFocus, showAddRow]); + useKeyboardEvent('Escape', () => { + if (!validationRef.current) onCancelAddColumn(); + else validationRef.current = false; + }); + return { watch, control, @@ -194,14 +205,16 @@ export function useSchema({ templateId }: UseSchemaProps) { formState, getValues, showAddRow, + validationRef, onMoveColumns, setShowAddRow, + getColumnTypes, + onAddColumnSubmit, onEditColumnClick, + onCancelAddColumn, onValidationsClick, onDeleteColumnClick, - getColumnTypes, isColumnCreateLoading, isLoading: isColumnListLoading, - handleSubmit: handleSubmit(onAddColumnSubmit), }; } diff --git a/apps/web/pages/imports/[id].tsx b/apps/web/pages/imports/[id].tsx index 8b9dc03f4..581488358 100644 --- a/apps/web/pages/imports/[id].tsx +++ b/apps/web/pages/imports/[id].tsx @@ -75,7 +75,7 @@ export default function ImportDetails({}) { {templateData?.name} - +