From fcfeed9301d248dd3082262505659ca4f72c4b55 Mon Sep 17 00:00:00 2001 From: KelvinTegelaar Date: Mon, 25 Mar 2024 17:16:46 +0100 Subject: [PATCH] bulk user adds --- src/routes.js | 8 + .../identity/administration/AddUserBulk.jsx | 256 ++++++++++++++++++ 2 files changed, 264 insertions(+) create mode 100644 src/views/identity/administration/AddUserBulk.jsx diff --git a/src/routes.js b/src/routes.js index 4f119b52d8c8..e5e5e35ebb9a 100644 --- a/src/routes.js +++ b/src/routes.js @@ -8,6 +8,8 @@ const Users = React.lazy(() => import('src/views/identity/administration/Users') const DeletedItems = React.lazy(() => import('src/views/identity/administration/Deleted')) const ViewBEC = React.lazy(() => import('src/views/identity/administration/ViewBEC')) const AddUser = React.lazy(() => import('src/views/identity/administration/AddUser')) +const AddUserBulk = React.lazy(() => import('src/views/identity/administration/AddUserBulk')) + const InviteGuest = React.lazy(() => import('src/views/identity/administration/InviteGuest')) const EditUser = React.lazy(() => import('src/views/identity/administration/EditUser')) const ViewUser = React.lazy(() => import('src/views/identity/administration/ViewUser')) @@ -251,6 +253,12 @@ const routes = [ { path: '/cipp/500', name: 'Error', component: Page500 }, { path: '/identity', name: 'Identity' }, { path: '/identity/administration/users/add', name: 'Add User', component: AddUser }, + { + path: '/identity/administration/users/addbulk', + name: 'Add User Bulk', + component: AddUserBulk, + }, + { path: '/identity/administration/users/edit', name: 'Edit User', component: EditUser }, { path: '/identity/administration/users/view', name: 'View User', component: ViewUser }, { diff --git a/src/views/identity/administration/AddUserBulk.jsx b/src/views/identity/administration/AddUserBulk.jsx new file mode 100644 index 000000000000..9b1e6dd3a507 --- /dev/null +++ b/src/views/identity/administration/AddUserBulk.jsx @@ -0,0 +1,256 @@ +import React, { useState } from 'react' +import { CButton, CCallout, CCol, CRow, CSpinner } from '@coreui/react' +import { Field, FormSpy } from 'react-final-form' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faExclamationTriangle, faPlus, faTrash } from '@fortawesome/free-solid-svg-icons' +import { CippCallout, CippWizard } from 'src/components/layout' +import PropTypes from 'prop-types' +import { RFFCFormInput } from 'src/components/forms' +import { CippTable } from 'src/components/tables' +import { CippCodeBlock, TenantSelector } from 'src/components/utilities' +import { CSVReader } from 'react-papaparse' +import { useLazyGenericPostRequestQuery } from 'src/store/api/app' +import { useSelector } from 'react-redux' + +const Error = ({ name }) => ( + + touched && error ? ( + + + {error} + + ) : null + } + /> +) + +Error.propTypes = { + name: PropTypes.string.isRequired, +} + +const AddUserBulk = () => { + const [genericPostRequest, postResults] = useLazyGenericPostRequestQuery() + const [BulkUser, setBulkUser] = useState([]) + const currentSettings = useSelector((state) => state.app) + const addedFields = currentSettings?.userSettingsDefaults?.defaultAttributes + ? //if we have default attributes, add the label object to the fields array + currentSettings.userSettingsDefaults.defaultAttributes.map((item) => item.label) + : [] + const fields = [ + 'givenName', + 'surName', + 'displayName', + 'mailNickName', + 'domain', + 'usageLocation', + 'JobTitle', + 'streetAddress', + 'PostalCode', + 'City', + 'State', + 'Department', + 'MobilePhone', + 'businessPhones', + ...addedFields, + ] + const columns = fields.map((field) => { + return { + name: field, + selector: (row) => row[field], + sortable: true, + } + }) + + const tableColumns = [ + ...columns, + { + name: 'Remove', + button: true, + cell: (row, index) => { + return ( + handleRemove(row)} size="sm" variant="ghost" color="danger"> + + + ) + }, + }, + ] + const valbutton = (value) => + BulkUser.length + ? undefined + : 'You must add at least one user. Did you forget to click add or upload the CSV?' + const handleOnDrop = (data) => { + const importdata = data.map((item) => { + //find any keys that have a null or blank string value, and remove them + Object.keys(item.data).forEach((key) => { + if (item.data[key] === null || item.data[key] === '') { + delete item.data[key] + } + }) + return item.data + }) + setBulkUser([...BulkUser, ...importdata]) + // console.log(importdata) + } + + const handleOnError = (err, file, inputElem, reason) => { + //set upload error + } + const tenantDomain = useSelector((state) => state.app.currentTenant.defaultDomainName) + + const handleSubmit = async (values) => { + const shippedValues = { + TenantFilter: tenantDomain, + BulkUser, + ...values, + } + //alert(JSON.stringify(values, null, 2)) + genericPostRequest({ path: '/api/AddUserBulk', values: shippedValues }) + } + const addRowtoData = (values) => { + setBulkUser((prevState) => { + if (prevState) { + return [values, ...prevState] + } else { + return [values] + } + }) + } + const handleRemove = async (itemindex) => { + let RemovedItems = BulkUser.filter((item) => item !== itemindex) + setBulkUser((prevState) => { + return RemovedItems + }) + } + return ( + + +
+

Step 1

+
Choose a tenant
+
+
+ {(props) => } + +
+
+ +
+

Step 2

+
Enter user information
+
+
+
+
+

+ + Example CSV + +

+
+ + + Drop CSV file here or click to upload. + + +

+ + {fields.map((field, idx) => { + return ( + + + + ) + })} + + + {/* eslint-disable react/prop-types */} + {(props) => { + return ( + <> + addRowtoData(props.values)} + name="addButton" + className="mb-3" + > + + Add + + + ) + }} + + + + + + + + {BulkUser && ( + + )} + + + +
+
+ +
+

Step 4

+
Confirm and apply
+
+ {postResults.isFetching && ( + + Loading + + )} +

+ {postResults.isSuccess && ( + { + return

  • {item}
  • + })} + callout={true} + calloutCopyValue={postResults.data?.Results} + /> + )} +

    + {BulkUser && ( + + )} +
    +
    +
    +
    + ) +} + +export default AddUserBulk