mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-03-08 01:53:30 +01:00
fix(editor): replace prompt/confirm with proper dialogs in BackendServicesPanel
Electron doesn't support browser prompt()/confirm() APIs. Replaced with: - Inline TextInput form for creating local backends - useConfirmationDialog hook for delete confirmations Fixes console error when clicking + button on Local Backends section.
This commit is contained in:
@@ -16,9 +16,11 @@ import { BackendServices, BackendServicesEvent } from '@noodl-models/BackendServ
|
|||||||
import { ActivityIndicator } from '@noodl-core-ui/components/common/ActivityIndicator';
|
import { ActivityIndicator } from '@noodl-core-ui/components/common/ActivityIndicator';
|
||||||
import { IconName, IconSize } from '@noodl-core-ui/components/common/Icon';
|
import { IconName, IconSize } from '@noodl-core-ui/components/common/Icon';
|
||||||
import { IconButton } from '@noodl-core-ui/components/inputs/IconButton';
|
import { IconButton } from '@noodl-core-ui/components/inputs/IconButton';
|
||||||
|
import { PrimaryButton, PrimaryButtonVariant, PrimaryButtonSize } from '@noodl-core-ui/components/inputs/PrimaryButton';
|
||||||
|
import { TextInput } from '@noodl-core-ui/components/inputs/TextInput';
|
||||||
import { Box } from '@noodl-core-ui/components/layout/Box';
|
import { Box } from '@noodl-core-ui/components/layout/Box';
|
||||||
import { Container } from '@noodl-core-ui/components/layout/Container';
|
import { Container } from '@noodl-core-ui/components/layout/Container';
|
||||||
import { VStack } from '@noodl-core-ui/components/layout/Stack';
|
import { HStack, VStack } from '@noodl-core-ui/components/layout/Stack';
|
||||||
import { useConfirmationDialog } from '@noodl-core-ui/components/popups/ConfirmationDialog/ConfirmationDialog.hooks';
|
import { useConfirmationDialog } from '@noodl-core-ui/components/popups/ConfirmationDialog/ConfirmationDialog.hooks';
|
||||||
import { BasePanel } from '@noodl-core-ui/components/sidebar/BasePanel';
|
import { BasePanel } from '@noodl-core-ui/components/sidebar/BasePanel';
|
||||||
import { Section, SectionVariant } from '@noodl-core-ui/components/sidebar/Section';
|
import { Section, SectionVariant } from '@noodl-core-ui/components/sidebar/Section';
|
||||||
@@ -36,6 +38,10 @@ export function BackendServicesPanel() {
|
|||||||
const [isAddDialogVisible, setIsAddDialogVisible] = useState(false);
|
const [isAddDialogVisible, setIsAddDialogVisible] = useState(false);
|
||||||
const [hasActivity, setHasActivity] = useState(false);
|
const [hasActivity, setHasActivity] = useState(false);
|
||||||
|
|
||||||
|
// Local backend creation state
|
||||||
|
const [isAddLocalVisible, setIsAddLocalVisible] = useState(false);
|
||||||
|
const [newLocalBackendName, setNewLocalBackendName] = useState('');
|
||||||
|
|
||||||
// Local backends hook
|
// Local backends hook
|
||||||
const {
|
const {
|
||||||
backends: localBackends,
|
backends: localBackends,
|
||||||
@@ -65,13 +71,42 @@ export function BackendServicesPanel() {
|
|||||||
setActiveBackendId(id);
|
setActiveBackendId(id);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Delete confirmation dialog
|
// Delete confirmation dialog for external backends
|
||||||
const [DeleteDialog, confirmDelete] = useConfirmationDialog({
|
const [DeleteDialog, confirmDelete] = useConfirmationDialog({
|
||||||
title: 'Delete Backend',
|
title: 'Delete Backend',
|
||||||
message: 'Are you sure you want to delete this backend configuration? This cannot be undone.',
|
message: 'Are you sure you want to delete this backend configuration? This cannot be undone.',
|
||||||
isDangerousAction: true
|
isDangerousAction: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Delete confirmation dialog for local backends
|
||||||
|
const [DeleteLocalDialog, confirmDeleteLocal] = useConfirmationDialog({
|
||||||
|
title: 'Delete Local Backend',
|
||||||
|
message: 'Delete this local backend? All data will be permanently lost.',
|
||||||
|
isDangerousAction: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle delete local backend
|
||||||
|
const handleDeleteLocalBackend = useCallback(
|
||||||
|
async (id: string) => {
|
||||||
|
try {
|
||||||
|
await confirmDeleteLocal();
|
||||||
|
await deleteLocalBackend(id);
|
||||||
|
} catch {
|
||||||
|
// User cancelled
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[confirmDeleteLocal, deleteLocalBackend]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Handle create local backend
|
||||||
|
const handleCreateLocalBackend = useCallback(async () => {
|
||||||
|
if (newLocalBackendName.trim()) {
|
||||||
|
await createLocalBackend(newLocalBackendName.trim());
|
||||||
|
setNewLocalBackendName('');
|
||||||
|
setIsAddLocalVisible(false);
|
||||||
|
}
|
||||||
|
}, [newLocalBackendName, createLocalBackend]);
|
||||||
|
|
||||||
// Handle delete backend
|
// Handle delete backend
|
||||||
const handleDeleteBackend = useCallback(
|
const handleDeleteBackend = useCallback(
|
||||||
async (id: string) => {
|
async (id: string) => {
|
||||||
@@ -124,6 +159,7 @@ export function BackendServicesPanel() {
|
|||||||
return (
|
return (
|
||||||
<BasePanel title="Backend Services" hasActivityBlocker={hasActivity} hasContentScroll>
|
<BasePanel title="Backend Services" hasActivityBlocker={hasActivity} hasContentScroll>
|
||||||
<DeleteDialog />
|
<DeleteDialog />
|
||||||
|
<DeleteLocalDialog />
|
||||||
|
|
||||||
{isLoading || isLoadingLocal ? (
|
{isLoading || isLoadingLocal ? (
|
||||||
<Container hasLeftSpacing hasTopSpacing>
|
<Container hasLeftSpacing hasTopSpacing>
|
||||||
@@ -136,19 +172,59 @@ export function BackendServicesPanel() {
|
|||||||
title="Local Backends"
|
title="Local Backends"
|
||||||
variant={SectionVariant.Panel}
|
variant={SectionVariant.Panel}
|
||||||
actions={
|
actions={
|
||||||
|
!isAddLocalVisible && (
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={IconName.Plus}
|
icon={IconName.Plus}
|
||||||
size={IconSize.Small}
|
size={IconSize.Small}
|
||||||
onClick={async () => {
|
onClick={() => setIsAddLocalVisible(true)}
|
||||||
const name = prompt('Enter backend name:');
|
|
||||||
if (name) {
|
|
||||||
await createLocalBackend(name);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
testId="add-local-backend-button"
|
testId="add-local-backend-button"
|
||||||
/>
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{/* Add Local Backend Form */}
|
||||||
|
{isAddLocalVisible && (
|
||||||
|
<Container hasLeftSpacing hasRightSpacing hasTopSpacing hasBottomSpacing>
|
||||||
|
<VStack>
|
||||||
|
<Text textType={TextType.DefaultContrast}>Create Local Backend</Text>
|
||||||
|
<Box hasTopSpacing>
|
||||||
|
<TextInput
|
||||||
|
value={newLocalBackendName}
|
||||||
|
onChange={(e) => setNewLocalBackendName(e.target.value)}
|
||||||
|
placeholder="Backend name"
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === 'Enter') handleCreateLocalBackend();
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
setIsAddLocalVisible(false);
|
||||||
|
setNewLocalBackendName('');
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box hasTopSpacing>
|
||||||
|
<HStack hasSpacing>
|
||||||
|
<PrimaryButton
|
||||||
|
label="Create"
|
||||||
|
size={PrimaryButtonSize.Small}
|
||||||
|
variant={PrimaryButtonVariant.Muted}
|
||||||
|
onClick={handleCreateLocalBackend}
|
||||||
|
isDisabled={!newLocalBackendName.trim()}
|
||||||
|
/>
|
||||||
|
<PrimaryButton
|
||||||
|
label="Cancel"
|
||||||
|
size={PrimaryButtonSize.Small}
|
||||||
|
variant={PrimaryButtonVariant.Muted}
|
||||||
|
onClick={() => {
|
||||||
|
setIsAddLocalVisible(false);
|
||||||
|
setNewLocalBackendName('');
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</HStack>
|
||||||
|
</Box>
|
||||||
|
</VStack>
|
||||||
|
</Container>
|
||||||
|
)}
|
||||||
|
|
||||||
{localBackends.length > 0 ? (
|
{localBackends.length > 0 ? (
|
||||||
<VStack>
|
<VStack>
|
||||||
{localBackends.map((backend) => (
|
{localBackends.map((backend) => (
|
||||||
@@ -157,15 +233,12 @@ export function BackendServicesPanel() {
|
|||||||
backend={backend}
|
backend={backend}
|
||||||
onStart={async () => startLocalBackend(backend.id)}
|
onStart={async () => startLocalBackend(backend.id)}
|
||||||
onStop={async () => stopLocalBackend(backend.id)}
|
onStop={async () => stopLocalBackend(backend.id)}
|
||||||
onDelete={() => {
|
onDelete={() => handleDeleteLocalBackend(backend.id)}
|
||||||
if (confirm('Delete this local backend? All data will be lost.')) {
|
|
||||||
deleteLocalBackend(backend.id);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</VStack>
|
</VStack>
|
||||||
) : (
|
) : (
|
||||||
|
!isAddLocalVisible && (
|
||||||
<Container hasLeftSpacing hasTopSpacing hasBottomSpacing>
|
<Container hasLeftSpacing hasTopSpacing hasBottomSpacing>
|
||||||
<Text>No local backends</Text>
|
<Text>No local backends</Text>
|
||||||
<Box hasTopSpacing>
|
<Box hasTopSpacing>
|
||||||
@@ -174,6 +247,7 @@ export function BackendServicesPanel() {
|
|||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</Container>
|
</Container>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user