fix: add content import functionality

This commit is contained in:
Emnaghz 2024-10-07 15:53:18 +01:00
parent e70c705d10
commit e0dd09d491
3 changed files with 126 additions and 0 deletions

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

View File

@ -9,6 +9,7 @@
import { faAlignLeft } from "@fortawesome/free-solid-svg-icons";
import AddIcon from "@mui/icons-material/Add";
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 Link from "next/link";
import { useRouter } from "next/router";
@ -38,6 +39,7 @@ import { PermissionAction } from "@/types/permission.types";
import { getDateTimeFormatter } from "@/utils/date";
import { ContentDialog } from "./ContentDialog";
import { ContentImportDialog } from "./ContentImportDialog";
export const Contents = () => {
const { t } = useTranslate();
@ -58,6 +60,9 @@ export const Contents = () => {
$eq: [{ entity: String(query.id) }],
$iLike: ["title"],
});
const importDialogCtl = useDialog<{
contentType?: IContentType;
}>(false);
const hasPermission = useHasPermission();
const { data: contentType } = useGet(String(query.id), {
entity: EntityType.CONTENT_TYPE,
@ -137,6 +142,18 @@ export const Contents = () => {
</Button>
</Grid>
) : 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>
</PageHeader>
</Grid>
@ -144,6 +161,7 @@ export const Contents = () => {
<Paper>
<ContentDialog {...getDisplayDialogs(addDialogCtl)} />
<ContentDialog {...getDisplayDialogs(editDialogCtl)} />
<ContentImportDialog {...getDisplayDialogs(importDialogCtl)} />
<DeleteDialog
{...deleteDialogCtl}
callback={() => {

View File

@ -35,6 +35,7 @@ export const ROUTES = {
RESET: "/user/reset",
NLP_SAMPLE_IMPORT: "/nlpsample/import",
NLP_SAMPLE_PREDICT: "/nlpsample/message",
CONTENT_IMPORT: "/content/import",
// Entities
[EntityType.SUBSCRIBER]: "/subscriber",
[EntityType.LABEL]: "/label",
@ -209,6 +210,14 @@ export class ApiClient {
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) {
const { data } = await this.request.get<INlpDatasetSampleAttributes>(
`${ROUTES.NLP_SAMPLE_PREDICT}`,