mirror of
https://github.com/hexastack/hexabot
synced 2025-03-16 10:28:54 +00:00
fix: add content import functionality
This commit is contained in:
parent
e70c705d10
commit
e0dd09d491
99
frontend/src/components/contents/ContentImportDialog.tsx
Normal file
99
frontend/src/components/contents/ContentImportDialog.tsx
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2024 Hexastack. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
|
||||||
|
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
|
||||||
|
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
|
import { Button, Dialog, DialogActions, DialogContent } from "@mui/material";
|
||||||
|
import { FC, useState } from "react";
|
||||||
|
import { useQuery } from "react-query";
|
||||||
|
|
||||||
|
import AttachmentInput from "@/app-components/attachment/AttachmentInput";
|
||||||
|
import { DialogTitle } from "@/app-components/dialogs/DialogTitle";
|
||||||
|
import { ContentContainer } from "@/app-components/dialogs/layouts/ContentContainer";
|
||||||
|
import { ContentItem } from "@/app-components/dialogs/layouts/ContentItem";
|
||||||
|
import { useApiClient } from "@/hooks/useApiClient";
|
||||||
|
import { DialogControlProps } from "@/hooks/useDialog";
|
||||||
|
import { useToast } from "@/hooks/useToast";
|
||||||
|
import { useTranslate } from "@/hooks/useTranslate";
|
||||||
|
import { IContentType } from "@/types/content-type.types";
|
||||||
|
|
||||||
|
export type ContentImportDialogProps = DialogControlProps<{
|
||||||
|
contentType?: IContentType;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export const ContentImportDialog: FC<ContentImportDialogProps> = ({
|
||||||
|
open,
|
||||||
|
data,
|
||||||
|
closeDialog,
|
||||||
|
...rest
|
||||||
|
}) => {
|
||||||
|
const [attachmentId, setAttachementId] = useState<string | null>(null);
|
||||||
|
const { t } = useTranslate();
|
||||||
|
const { toast } = useToast();
|
||||||
|
const { apiClient } = useApiClient();
|
||||||
|
const { refetch, isFetching } = useQuery(
|
||||||
|
["importContent", data?.contentType?.id, attachmentId],
|
||||||
|
async () => {
|
||||||
|
await apiClient.importContent(data?.contentType?.id!, attachmentId!)},
|
||||||
|
{
|
||||||
|
enabled: false,
|
||||||
|
onSuccess: () => {
|
||||||
|
handleCloseDialog();
|
||||||
|
toast.success(t("message.success_save"));
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
toast.error(t("message.internal_server_error"));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const handleCloseDialog = () => {
|
||||||
|
closeDialog();
|
||||||
|
setAttachementId(null);
|
||||||
|
};
|
||||||
|
const handleImportClick = () => {
|
||||||
|
if (attachmentId && data?.contentType?.id) {
|
||||||
|
refetch();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} fullWidth onClose={handleCloseDialog} {...rest}>
|
||||||
|
<DialogTitle onClose={handleCloseDialog}>{t("title.import")}</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<ContentContainer>
|
||||||
|
<ContentItem>
|
||||||
|
<AttachmentInput
|
||||||
|
format="basic"
|
||||||
|
accept="text/csv"
|
||||||
|
onChange={(id, _) => {
|
||||||
|
setAttachementId(id);
|
||||||
|
}}
|
||||||
|
label=""
|
||||||
|
value={attachmentId}
|
||||||
|
/>
|
||||||
|
</ContentItem>
|
||||||
|
</ContentContainer>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
disabled={!attachmentId || isFetching}
|
||||||
|
onClick={handleImportClick}
|
||||||
|
>
|
||||||
|
{t("button.import")}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
startIcon={<CloseIcon />}
|
||||||
|
variant="outlined"
|
||||||
|
onClick={handleCloseDialog}
|
||||||
|
disabled={isFetching}
|
||||||
|
>
|
||||||
|
{t("button.cancel")}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
@ -9,6 +9,7 @@
|
|||||||
import { faAlignLeft } from "@fortawesome/free-solid-svg-icons";
|
import { faAlignLeft } from "@fortawesome/free-solid-svg-icons";
|
||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
||||||
|
import UploadIcon from "@mui/icons-material/Upload";
|
||||||
import { Button, Chip, Grid, Paper, Switch, Typography } from "@mui/material";
|
import { Button, Chip, Grid, Paper, Switch, Typography } from "@mui/material";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
@ -38,6 +39,7 @@ import { PermissionAction } from "@/types/permission.types";
|
|||||||
import { getDateTimeFormatter } from "@/utils/date";
|
import { getDateTimeFormatter } from "@/utils/date";
|
||||||
|
|
||||||
import { ContentDialog } from "./ContentDialog";
|
import { ContentDialog } from "./ContentDialog";
|
||||||
|
import { ContentImportDialog } from "./ContentImportDialog";
|
||||||
|
|
||||||
export const Contents = () => {
|
export const Contents = () => {
|
||||||
const { t } = useTranslate();
|
const { t } = useTranslate();
|
||||||
@ -58,6 +60,9 @@ export const Contents = () => {
|
|||||||
$eq: [{ entity: String(query.id) }],
|
$eq: [{ entity: String(query.id) }],
|
||||||
$iLike: ["title"],
|
$iLike: ["title"],
|
||||||
});
|
});
|
||||||
|
const importDialogCtl = useDialog<{
|
||||||
|
contentType?: IContentType;
|
||||||
|
}>(false);
|
||||||
const hasPermission = useHasPermission();
|
const hasPermission = useHasPermission();
|
||||||
const { data: contentType } = useGet(String(query.id), {
|
const { data: contentType } = useGet(String(query.id), {
|
||||||
entity: EntityType.CONTENT_TYPE,
|
entity: EntityType.CONTENT_TYPE,
|
||||||
@ -137,6 +142,18 @@ export const Contents = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
) : null}
|
) : null}
|
||||||
|
{hasPermission(EntityType.CONTENT, PermissionAction.CREATE) ? (
|
||||||
|
<Grid item>
|
||||||
|
<Button
|
||||||
|
startIcon={<UploadIcon />}
|
||||||
|
variant="contained"
|
||||||
|
onClick={() => importDialogCtl.openDialog({ contentType })}
|
||||||
|
sx={{ float: "right" }}
|
||||||
|
>
|
||||||
|
{t("button.import")}
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
) : null}
|
||||||
</Grid>
|
</Grid>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -144,6 +161,7 @@ export const Contents = () => {
|
|||||||
<Paper>
|
<Paper>
|
||||||
<ContentDialog {...getDisplayDialogs(addDialogCtl)} />
|
<ContentDialog {...getDisplayDialogs(addDialogCtl)} />
|
||||||
<ContentDialog {...getDisplayDialogs(editDialogCtl)} />
|
<ContentDialog {...getDisplayDialogs(editDialogCtl)} />
|
||||||
|
<ContentImportDialog {...getDisplayDialogs(importDialogCtl)} />
|
||||||
<DeleteDialog
|
<DeleteDialog
|
||||||
{...deleteDialogCtl}
|
{...deleteDialogCtl}
|
||||||
callback={() => {
|
callback={() => {
|
||||||
|
@ -35,6 +35,7 @@ export const ROUTES = {
|
|||||||
RESET: "/user/reset",
|
RESET: "/user/reset",
|
||||||
NLP_SAMPLE_IMPORT: "/nlpsample/import",
|
NLP_SAMPLE_IMPORT: "/nlpsample/import",
|
||||||
NLP_SAMPLE_PREDICT: "/nlpsample/message",
|
NLP_SAMPLE_PREDICT: "/nlpsample/message",
|
||||||
|
CONTENT_IMPORT: "/content/import",
|
||||||
// Entities
|
// Entities
|
||||||
[EntityType.SUBSCRIBER]: "/subscriber",
|
[EntityType.SUBSCRIBER]: "/subscriber",
|
||||||
[EntityType.LABEL]: "/label",
|
[EntityType.LABEL]: "/label",
|
||||||
@ -209,6 +210,14 @@ export class ApiClient {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async importContent(contentTypeId: string, attachementId: string) {
|
||||||
|
const { data } = await this.request.get(
|
||||||
|
`${ROUTES.CONTENT_IMPORT}/${contentTypeId}/${attachementId}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
async predictNlp(text: string) {
|
async predictNlp(text: string) {
|
||||||
const { data } = await this.request.get<INlpDatasetSampleAttributes>(
|
const { data } = await this.request.get<INlpDatasetSampleAttributes>(
|
||||||
`${ROUTES.NLP_SAMPLE_PREDICT}`,
|
`${ROUTES.NLP_SAMPLE_PREDICT}`,
|
||||||
|
Loading…
Reference in New Issue
Block a user