diff --git a/ui/package-lock.json b/ui/package-lock.json index 9df9ebb85..9eac1591e 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -24,7 +24,7 @@ "@types/react-router-dom": "^5.3.3", "axios": "^1.6.7", "crypto": "^1.0.1", - "getindexify": "^0.0.45", + "getindexify": "^0.0.46", "moment": "^2.30.1", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -9728,9 +9728,9 @@ } }, "node_modules/getindexify": { - "version": "0.0.45", - "resolved": "https://registry.npmjs.org/getindexify/-/getindexify-0.0.45.tgz", - "integrity": "sha512-6J+e90QCjl4ZHnr6lqWQxH0+d0XrUNKyXNYhKQa/0ToL0k2ZyV4gq8mdGcQ+yQs/1JUE3d06csf2gDDroPjRxw==", + "version": "0.0.46", + "resolved": "https://registry.npmjs.org/getindexify/-/getindexify-0.0.46.tgz", + "integrity": "sha512-l1/nSljavVpmbYZ4FIRgeRXcNq5op4sSrzizCtH+YWFAbJFA09fQWOmZqGnomrbjAv+zhidPh1GYOYkN/BO9HQ==", "dependencies": { "axios": "^1.6.7", "crypto-js": "^4.2.0", diff --git a/ui/package.json b/ui/package.json index 12e318804..6a25981ef 100644 --- a/ui/package.json +++ b/ui/package.json @@ -20,7 +20,7 @@ "@types/react-router-dom": "^5.3.3", "axios": "^1.6.7", "crypto": "^1.0.1", - "getindexify": "^0.0.45", + "getindexify": "^0.0.46", "moment": "^2.30.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/ui/src/components/Inputs/LabelsInput.tsx b/ui/src/components/Inputs/LabelsInput.tsx new file mode 100644 index 000000000..8f373969f --- /dev/null +++ b/ui/src/components/Inputs/LabelsInput.tsx @@ -0,0 +1,105 @@ +import { Box, TextField, IconButton, Typography } from '@mui/material' +import { Add, Delete } from '@mui/icons-material' +import { useState } from 'react' + +interface LabelsInputProps { + onChange: (labels: Record) => void + disabled: boolean +} + +const LabelsInput = ({ onChange, disabled }: LabelsInputProps) => { + const [labels, setLabels] = useState>({}) + const [newKey, setNewKey] = useState('') + const [newValue, setNewValue] = useState('') + + const handleAddLabel = () => { + if (newKey && newValue) { + const updatedLabels = { ...labels, [newKey]: newValue } + setLabels(updatedLabels) + onChange(updatedLabels) + setNewKey('') + setNewValue('') + } + } + + const handleDeleteLabel = (key: string) => { + const { [key]: _, ...remainingLabels } = labels + setLabels(remainingLabels) + onChange(remainingLabels) + } + + const handleChange = + (setValue: React.Dispatch>) => + (e: React.ChangeEvent) => { + const regex = /^[a-zA-Z0-9-_]*$/ + if (regex.test(e.target.value)) { + setValue(e.target.value) + } + } + + return ( + + + Labels + + + + + + + + + {Object.entries(labels).map(([key, value]) => ( + + + + handleDeleteLabel(key)} + > + + + + ))} + + ) +} + +export default LabelsInput diff --git a/ui/src/components/UploadButton.tsx b/ui/src/components/UploadButton.tsx new file mode 100644 index 000000000..83c532fdf --- /dev/null +++ b/ui/src/components/UploadButton.tsx @@ -0,0 +1,154 @@ +import UploadIcon from '@mui/icons-material/Upload' +import { + Box, + Button, + Modal, + Typography, + MenuItem, + Select, + Paper, + CircularProgress, +} from '@mui/material' +import { ExtractionGraph, IndexifyClient } from 'getindexify' +import { useState } from 'react' +import LabelsInput from './Inputs/LabelsInput' + +interface Props { + client: IndexifyClient +} + +const UploadButton = ({ client }: Props) => { + const [open, setOpen] = useState(false) + const [file, setFile] = useState(null) + const [labels, setLabels] = useState>({}) + const [fileName, setFileName] = useState('') + const [extractionGraphName, setExtractionGraphName] = useState('') + const [loading, setLoading] = useState(false) + const [extractionGraphs, setExtractionGraphs] = useState( + client.extractionGraphs + ) + + const handleOpen = () => setOpen(true) + const handleClose = () => setOpen(false) + + const handleFileChange = (event: React.ChangeEvent) => { + if (event.target.files && event.target.files[0]) { + setFile(event.target.files[0]) + setFileName(event.target.files[0].name) + } + } + + const modalStyle = { + position: 'absolute' as 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: '80%', + maxWidth: '800px', + bgcolor: 'background.paper', + maxHeight: '100%', + overflow: 'scroll', + boxShadow: 24, + p: 4, + } + + const upload = async () => { + if (file && extractionGraphName) { + setLoading(true) + await client.uploadFile(extractionGraphName, file, labels) + window.location.reload() + } + } + + const updateExtractionGraphs = async () => { + const graphs = await client.getExtractionGraphs() + setExtractionGraphs(graphs) + } + + return ( + <> + + + + Upload Content + + + Select a file to upload and choose an extraction graph. + + + + + {fileName && ( + + Selected File: {fileName} + + )} + + { + setLabels(val) + }} + /> + + + + {loading && ( + + )} + + + + + + ) +} + +export default UploadButton diff --git a/ui/src/components/tables/ContentTable.tsx b/ui/src/components/tables/ContentTable.tsx index 04c6dee1b..2da82eb7e 100644 --- a/ui/src/components/tables/ContentTable.tsx +++ b/ui/src/components/tables/ContentTable.tsx @@ -1,5 +1,5 @@ import { DataGrid, GridColDef } from '@mui/x-data-grid' -import { IContentMetadata, IExtractionPolicy } from 'getindexify' +import { IContentMetadata, IndexifyClient } from 'getindexify' import { Alert, Button, @@ -17,12 +17,13 @@ import moment from 'moment' import { Link } from 'react-router-dom' import CopyText from '../CopyText' import { IContentMetadataExtended } from '../../types' +import UploadButton from '../UploadButton' const ContentTable = ({ - extractionPolicies, loadData, + client, }: { - extractionPolicies: IExtractionPolicy[] + client: IndexifyClient, loadData: ({ pageSize, parentId, @@ -136,9 +137,7 @@ const ContentTable = ({ headerName: '', width: 100, renderCell: (params) => ( - + @@ -269,6 +268,7 @@ const ContentTable = ({ + { graph.extraction_policies) - .flat()} + client={client} /> ) diff --git a/ui/src/routes/Namespace/index.tsx b/ui/src/routes/Namespace/index.tsx index 735a6e24e..59da34299 100644 --- a/ui/src/routes/Namespace/index.tsx +++ b/ui/src/routes/Namespace/index.tsx @@ -87,9 +87,7 @@ const NamespacePage = () => { graph.extraction_policies) - .flat()} + client={client} />