github.com/minio/console@v1.4.1/web-app/src/screens/Console/IDP/LDAP/LDAPEntitiesQuery.tsx (about)

     1  // This file is part of MinIO Console Server
     2  // Copyright (c) 2023 MinIO, Inc.
     3  //
     4  // This program is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Affero General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // This program is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  // GNU Affero General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Affero General Public License
    15  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  
    17  import React, { Fragment, useState } from "react";
    18  import {
    19    AddIcon,
    20    Box,
    21    Button,
    22    Grid,
    23    InputBox,
    24    Loader,
    25    RemoveIcon,
    26    SearchIcon,
    27    SectionTitle,
    28    TimeIcon,
    29  } from "mds";
    30  import { useSelector } from "react-redux";
    31  import { DateTime } from "luxon";
    32  import { api } from "api";
    33  import { errorToHandler } from "api/errors";
    34  import { LdapEntities } from "api/consoleApi";
    35  import { setErrorSnackMessage } from "../../../../systemSlice";
    36  import { AppState, useAppDispatch } from "../../../../store";
    37  import LDAPResultsBlock from "./LDAPResultsBlock";
    38  import PolicySelectors from "../../Policies/PolicySelectors";
    39  
    40  const LDAPEntitiesQuery = () => {
    41    const dispatch = useAppDispatch();
    42  
    43    const [loading, setLoading] = useState<boolean>(false);
    44    const [users, setUsers] = useState<string[]>([""]);
    45    const [groups, setGroups] = useState<string[]>([""]);
    46    const [results, setResults] = useState<LdapEntities | null>(null);
    47  
    48    const selectedPolicies = useSelector(
    49      (state: AppState) => state.createUser.selectedPolicies,
    50    );
    51  
    52    const searchEntities = () => {
    53      setLoading(true);
    54  
    55      let data: any = {};
    56  
    57      let cleanPolicies = selectedPolicies.filter((pol) => pol !== "");
    58      let cleanUsers = users.filter((usr) => usr !== "");
    59      let cleanGroups = groups.filter((grp) => grp !== "");
    60  
    61      if (cleanPolicies.length > 0) {
    62        data["policies"] = cleanPolicies;
    63      }
    64  
    65      if (cleanUsers.length > 0) {
    66        data["users"] = cleanUsers;
    67      }
    68  
    69      if (cleanGroups.length > 0) {
    70        data["groups"] = cleanGroups;
    71      }
    72  
    73      api.ldapEntities
    74        .getLdapEntities(data)
    75        .then((result) => {
    76          setResults(result.data);
    77          setLoading(false);
    78        })
    79        .catch((err) => {
    80          dispatch(setErrorSnackMessage(errorToHandler(err.error)));
    81          setLoading(false);
    82        });
    83    };
    84  
    85    const alterUsersList = (addItem: boolean, index: number) => {
    86      if (addItem) {
    87        const alterUsers = [...users, ""];
    88        setUsers(alterUsers);
    89  
    90        return;
    91      }
    92  
    93      const filteredUsers = users.filter((_, indx) => indx !== index);
    94  
    95      setUsers(filteredUsers);
    96    };
    97  
    98    const alterGroupsList = (addItem: boolean, index: number) => {
    99      if (addItem) {
   100        const alterGroups = [...groups, ""];
   101        setGroups(alterGroups);
   102  
   103        return;
   104      }
   105  
   106      const filteredGroups = groups.filter((_, indx) => indx !== index);
   107  
   108      setGroups(filteredGroups);
   109    };
   110  
   111    return (
   112      <Box sx={{ marginTop: 15, paddingTop: 0 }}>
   113        <Grid container sx={{ marginTop: 5 }}>
   114          <Grid item sm={12} md={6} lg={5} sx={{ padding: 10, paddingTop: 0 }}>
   115            <SectionTitle>Query Filters</SectionTitle>
   116  
   117            <Box
   118              sx={{
   119                padding: "0 10px",
   120                display: "flex",
   121                flexDirection: "column",
   122                gap: 40,
   123              }}
   124            >
   125              <Box sx={{ padding: "10px 26px" }} withBorders>
   126                <Box sx={{ display: "flex" }}>
   127                  <h4 style={{ margin: 0, marginBottom: 10, fontSize: 14 }}>
   128                    Users
   129                  </h4>
   130                </Box>
   131                <Box
   132                  sx={{
   133                    overflowY: "auto",
   134                    minHeight: 50,
   135                    maxHeight: 250,
   136                    "& > div > div": {
   137                      width: "100%",
   138                    },
   139                  }}
   140                >
   141                  {users.map((userDat, index) => {
   142                    return (
   143                      <InputBox
   144                        id={`search-user-${index}`}
   145                        key={`search-user-${index}`}
   146                        value={userDat}
   147                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
   148                          const usersElements = [...users];
   149                          usersElements[index] = e.target.value;
   150                          setUsers(usersElements);
   151                        }}
   152                        overlayIcon={
   153                          users.length === index + 1 ? (
   154                            <AddIcon />
   155                          ) : (
   156                            <RemoveIcon />
   157                          )
   158                        }
   159                        overlayAction={() => {
   160                          alterUsersList(users.length === index + 1, index);
   161                        }}
   162                      />
   163                    );
   164                  })}
   165                </Box>
   166              </Box>
   167              <Box sx={{ padding: "10px 26px" }} withBorders>
   168                <h4 style={{ margin: 0, marginBottom: 10, fontSize: 14 }}>
   169                  Groups
   170                </h4>
   171                <Box
   172                  sx={{
   173                    overflowY: "auto",
   174                    minHeight: 50,
   175                    maxHeight: "calc(100vh - 340px)",
   176                    "& > div > div": {
   177                      width: "100%",
   178                    },
   179                  }}
   180                >
   181                  {groups.map((groupDat, index) => {
   182                    return (
   183                      <InputBox
   184                        id={`search-group-${index}`}
   185                        key={`search-group-${index}`}
   186                        value={groupDat}
   187                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
   188                          const groupsElements = [...groups];
   189                          groupsElements[index] = e.target.value;
   190                          setGroups(groupsElements);
   191                        }}
   192                        overlayIcon={
   193                          groups.length === index + 1 ? (
   194                            <AddIcon />
   195                          ) : (
   196                            <RemoveIcon />
   197                          )
   198                        }
   199                        overlayAction={() => {
   200                          alterGroupsList(groups.length === index + 1, index);
   201                        }}
   202                      />
   203                    );
   204                  })}
   205                </Box>
   206              </Box>
   207              <Box sx={{ padding: "10px 26px" }} withBorders>
   208                <h4 style={{ margin: 0, marginBottom: 10, fontSize: 14 }}>
   209                  Policies
   210                </h4>
   211                <Box
   212                  sx={{
   213                    minHeight: 265,
   214                    maxHeight: "calc(100vh - 740px)",
   215                  }}
   216                >
   217                  <PolicySelectors selectedPolicy={selectedPolicies} noTitle />
   218                </Box>
   219              </Box>
   220            </Box>
   221          </Grid>
   222          <Grid
   223            item
   224            sm={12}
   225            md={6}
   226            lg={7}
   227            sx={{
   228              padding: 10,
   229              paddingTop: 0,
   230              display: "flex",
   231              flexDirection: "column",
   232            }}
   233          >
   234            {loading ? (
   235              <Box sx={{ textAlign: "center" }}>
   236                <Loader />
   237              </Box>
   238            ) : (
   239              <Fragment>
   240                <SectionTitle
   241                  actions={
   242                    <Box
   243                      sx={{
   244                        display: "flex",
   245                        flexDirection: "row",
   246                        alignItems: "center",
   247                        fontSize: 14,
   248                      }}
   249                    >
   250                      {results?.timestamp ? (
   251                        <Fragment>
   252                          <TimeIcon
   253                            style={{
   254                              width: 14,
   255                              height: 14,
   256                              marginRight: 5,
   257                              fill: "#BEBFBF",
   258                            }}
   259                          />
   260                          {DateTime.fromISO(results.timestamp).toFormat(
   261                            "D HH:mm:ss",
   262                          )}
   263                        </Fragment>
   264                      ) : (
   265                        ""
   266                      )}
   267                    </Box>
   268                  }
   269                >
   270                  Query Results
   271                </SectionTitle>
   272                {results ? (
   273                  <Box
   274                    sx={{
   275                      backgroundColor: "#FBFAFA",
   276                      padding: "8px 22px",
   277                      flexGrow: 1,
   278                      overflowY: "auto",
   279                    }}
   280                  >
   281                    {!results.groups && !results.users && !results.policies && (
   282                      <Box sx={{ textAlign: "center" }}>
   283                        <h4>No Results Available</h4>
   284                      </Box>
   285                    )}
   286                    {!!results.groups && (
   287                      <LDAPResultsBlock results={results} entityName={"Group"} />
   288                    )}
   289                    {!!results.users && (
   290                      <LDAPResultsBlock results={results} entityName={"User"} />
   291                    )}
   292                    {!!results.policies && (
   293                      <LDAPResultsBlock results={results} entityName={"Policy"} />
   294                    )}
   295                  </Box>
   296                ) : (
   297                  <Box sx={{ textAlign: "center" }}>No query results yet</Box>
   298                )}
   299              </Fragment>
   300            )}
   301          </Grid>
   302        </Grid>
   303        <Grid container>
   304          <Grid
   305            item
   306            xs={12}
   307            sx={{
   308              display: "flex",
   309              justifyContent: "flex-start",
   310              marginTop: 45,
   311              padding: "0 20px",
   312            }}
   313          >
   314            <Button
   315              id={"search-entity"}
   316              type={"button"}
   317              variant={"callAction"}
   318              onClick={searchEntities}
   319              icon={<SearchIcon />}
   320            >
   321              Search
   322            </Button>
   323          </Grid>
   324        </Grid>
   325      </Box>
   326    );
   327  };
   328  
   329  export default LDAPEntitiesQuery;