Skip to content

Commit

Permalink
feat(FR-592): NEO vfolder page - delete folders
Browse files Browse the repository at this point in the history
  • Loading branch information
agatha197 committed Feb 27, 2025
1 parent 24d473a commit 3baabe1
Show file tree
Hide file tree
Showing 27 changed files with 456 additions and 62 deletions.
93 changes: 93 additions & 0 deletions react/src/components/BAIConfirmModalWithInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import BAIModal, { BAIModalProps } from './BAIModal';
import Flex from './Flex';
import { ExclamationCircleFilled } from '@ant-design/icons';
import { Form, Input, Typography } from 'antd';
import _ from 'lodash';
import React from 'react';
import { useTranslation } from 'react-i18next';

const { Text } = Typography;

interface BAIConfirmModalWithInputProps extends Omit<BAIModalProps, 'icon'> {
confirmText: string;
content: React.ReactNode;
title: React.ReactNode;
icon?: React.ReactNode;
}

const BAIConfirmModalWithInput: React.FC<BAIConfirmModalWithInputProps> = ({
confirmText,
title,
content,
icon,
onOk,
onCancel,
...props
}) => {
const { t } = useTranslation();
const [form] = Form.useForm();
const typedText = Form.useWatch('confirmText', form);

return (
<BAIModal
destroyOnClose
title={
<Flex direction="column" justify="start" align="start">
<Text strong>
{icon ?? (
<ExclamationCircleFilled
style={{ color: '#faad14', marginRight: 5 }}
/>
)}
{title}
</Text>
</Flex>
}
onOk={(e) => {
form.resetFields();
_.isFunction(onOk) && onOk(e);
}}
onCancel={(e) => {
form.resetFields();
_.isFunction(onCancel) && onCancel(e);
}}
okButtonProps={{ disabled: confirmText !== typedText, danger: true }}
{...props}
>
<Flex direction="column" justify="start" align="start">
{content}
<Form form={form} style={{ width: '100%' }} preserve={false}>
<Form.Item
name="confirmText"
rules={[
{
required: true,
message: t('dialog.PleaseTypeToConfirm', {
confirmText,
}),
validator: (_, value) => {
if (value === confirmText) {
return Promise.resolve();
}
return Promise.reject();
},
},
]}
>
<Input
autoFocus
autoComplete="off"
allowClear
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
}}
/>
</Form.Item>
</Form>
</Flex>
</BAIModal>
);
};

export default BAIConfirmModalWithInput;
89 changes: 89 additions & 0 deletions react/src/components/DeleteVFolderModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { toLocalId } from '../helper';
import { useSuspendedBackendaiClient } from '../hooks';
import { useTanMutation } from '../hooks/reactQueryAlias';
import { useSetBAINotification } from '../hooks/useBAINotification';
import { usePainKiller } from '../hooks/usePainKiller';
import BAIModal, { BAIModalProps } from './BAIModal';
import { DeleteVFolderModalFragment$key } from './__generated__/DeleteVFolderModalFragment.graphql';
import { VFolderNodesFragment$data } from './__generated__/VFolderNodesFragment.graphql';
import { Typography } from 'antd';
import graphql from 'babel-plugin-relay/macro';
import _ from 'lodash';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useFragment } from 'react-relay';

type VFolderType = NonNullable<VFolderNodesFragment$data[number]>;

interface DeleteVFolderModalProps extends BAIModalProps {
vfolderFrgmts?: DeleteVFolderModalFragment$key;
onRequestClose?: (success: boolean) => void;
}

const DeleteVFolderModal: React.FC<DeleteVFolderModalProps> = ({
vfolderFrgmts,
onRequestClose,
...baiModalProps
}) => {
const { t } = useTranslation();
const { upsertNotification } = useSetBAINotification();
const baiClient = useSuspendedBackendaiClient();
const painKiller = usePainKiller();

const vfolders = useFragment(
graphql`
fragment DeleteVFolderModalFragment on VirtualFolderNode
@relay(plural: true) {
id
name
}
`,
vfolderFrgmts,
);

const deleteMutation = useTanMutation({
mutationFn: (id: string) => {
return baiClient.vfolder.delete_by_id(toLocalId(id));
},
});

return (
<BAIModal
title={t('data.folders.MoveToTrash')}
centered
okText={t('data.folders.Delete')}
okButtonProps={{ danger: true }}
onCancel={() => onRequestClose?.(false)}
onOk={() => {
const promises = _.map(vfolders, (vfolder: VFolderType) =>
deleteMutation.mutateAsync(vfolder.id).catch((error) => {
upsertNotification({
message: painKiller.relieve(error?.title),
description: error?.description,
open: true,
});
}),
);
Promise.allSettled(promises).then((results) => {
const success = results.every(
(result) => result.status === 'fulfilled',
);
onRequestClose?.(success);
});
}}
{...baiModalProps}
>
<Typography.Text>
{vfolders?.length === 1
? t('data.folders.MoveToTrashDescription', {
folderName: vfolders?.[0]?.name,
})
: t('data.folders.MoveToTrashMultipleDescription', {
folderLength: vfolders?.length,
})}
</Typography.Text>
</BAIModal>
);
};

export default DeleteVFolderModal;
5 changes: 2 additions & 3 deletions react/src/components/FolderCreateModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ interface FolderCreateFormItemsType {
group: string | undefined;
usage_mode: 'general' | 'model';
type: 'user' | 'project';
permission: 'rw' | 'ro' | 'wd';
permission: 'rw' | 'ro';
cloneable: boolean;
}

Expand All @@ -69,7 +69,7 @@ export interface FolderCreationResponse {
quota_scope_id: string;
host: string;
usage_mode: 'general' | 'model';
permission: 'rw' | 'ro' | 'wd';
permission: 'rw' | 'ro';
max_size: number;
creator: string;
ownership_type: 'user' | 'project';
Expand Down Expand Up @@ -303,7 +303,6 @@ const FolderCreateModal: React.FC<FolderCreateModalProps> = ({
<Radio.Group>
<Radio value={'rw'}>Read & Write</Radio>
<Radio value={'ro'}>Read Only</Radio>
<Radio value={'wd'}>Delete</Radio>
</Radio.Group>
</Form.Item>

Expand Down
Loading

0 comments on commit 3baabe1

Please sign in to comment.