mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-18 05:10:45 +00:00
SPRINT-20: updates to saved filters based on ui feedback
This commit is contained in:
@ -50,7 +50,7 @@
|
|||||||
"clean": "rm -rf node_modules package-lock.json",
|
"clean": "rm -rf node_modules package-lock.json",
|
||||||
"eject": "react-scripts eject",
|
"eject": "react-scripts eject",
|
||||||
"geff-ham": "rm -rf node_modules/ && rm -rf package-lock.json && rm -rf lib/ && npm install",
|
"geff-ham": "rm -rf node_modules/ && rm -rf package-lock.json && rm -rf lib/ && npm install",
|
||||||
"install-legacy-peer-deps": "npm install --legacy-peer-deps",
|
"npm-install": "npm install",
|
||||||
"prepublishOnly": "tsc -p ./ --outDir lib/",
|
"prepublishOnly": "tsc -p ./ --outDir lib/",
|
||||||
"start": "BROWSER=none react-scripts start",
|
"start": "BROWSER=none react-scripts start",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
|
@ -111,6 +111,7 @@ export function QActionsMenuButton({isOpen, onClickHandler}: QActionsMenuButtonP
|
|||||||
variant={isOpen ? "contained" : "outlined"}
|
variant={isOpen ? "contained" : "outlined"}
|
||||||
color="dark"
|
color="dark"
|
||||||
onClick={onClickHandler}
|
onClick={onClickHandler}
|
||||||
|
startIcon={<Icon>games</Icon>}
|
||||||
fullWidth
|
fullWidth
|
||||||
>
|
>
|
||||||
actions
|
actions
|
||||||
@ -129,6 +130,7 @@ export function QSavedFiltersMenuButton({isOpen, onClickHandler}: QActionsMenuBu
|
|||||||
color="dark"
|
color="dark"
|
||||||
onClick={onClickHandler}
|
onClick={onClickHandler}
|
||||||
fullWidth
|
fullWidth
|
||||||
|
startIcon={<Icon>filter_alt</Icon>}
|
||||||
>
|
>
|
||||||
saved filters
|
saved filters
|
||||||
<Icon>keyboard_arrow_down</Icon>
|
<Icon>keyboard_arrow_down</Icon>
|
||||||
|
@ -25,7 +25,7 @@ import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QT
|
|||||||
import {QJobComplete} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobComplete";
|
import {QJobComplete} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobComplete";
|
||||||
import {QJobError} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobError";
|
import {QJobError} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobError";
|
||||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||||
import {KeyboardArrowDown} from "@mui/icons-material";
|
import {FiberManualRecord, KeyboardArrowDown} from "@mui/icons-material";
|
||||||
import {Alert, ClickAwayListener, Grow, MenuList, Paper, Popper} from "@mui/material";
|
import {Alert, ClickAwayListener, Grow, MenuList, Paper, Popper} from "@mui/material";
|
||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Button from "@mui/material/Button";
|
import Button from "@mui/material/Button";
|
||||||
@ -34,9 +34,13 @@ import Dialog from "@mui/material/Dialog";
|
|||||||
import DialogActions from "@mui/material/DialogActions";
|
import DialogActions from "@mui/material/DialogActions";
|
||||||
import DialogContent from "@mui/material/DialogContent";
|
import DialogContent from "@mui/material/DialogContent";
|
||||||
import DialogTitle from "@mui/material/DialogTitle";
|
import DialogTitle from "@mui/material/DialogTitle";
|
||||||
|
import Divider from "@mui/material/Divider";
|
||||||
|
import Icon from "@mui/material/Icon";
|
||||||
|
import ListItemIcon from "@mui/material/ListItemIcon";
|
||||||
import Menu from "@mui/material/Menu";
|
import Menu from "@mui/material/Menu";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
|
import Tooltip from "@mui/material/Tooltip";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import {GridFilterModel, GridSortItem} from "@mui/x-data-grid-pro";
|
import {GridFilterModel, GridSortItem} from "@mui/x-data-grid-pro";
|
||||||
import FormData from "form-data";
|
import FormData from "form-data";
|
||||||
@ -76,12 +80,12 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
|
|||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const [saveOptionsOpen, setSaveOptionsOpen] = useState(false);
|
const [saveOptionsOpen, setSaveOptionsOpen] = useState(false);
|
||||||
|
|
||||||
const SAVE_OPTION = "Save Filter...";
|
const SAVE_OPTION = "Save...";
|
||||||
const SAVE_AS_OPTION = "Create A New Filter From This Filter...";
|
const DUPLICATE_OPTION = "Duplicate...";
|
||||||
const RENAME_OPTION = "Rename This Filter...";
|
const RENAME_OPTION = "Rename...";
|
||||||
const CLEAR_OPTION = "Clear This Filter";
|
const DELETE_OPTION = "Delete...";
|
||||||
const DELETE_OPTION = "Delete This Filter...";
|
const CLEAR_OPTION = "Clear Current Filter";
|
||||||
const dropdownOptions = [SAVE_AS_OPTION, RENAME_OPTION, CLEAR_OPTION, DELETE_OPTION];
|
const dropdownOptions = [DUPLICATE_OPTION, RENAME_OPTION, DELETE_OPTION, CLEAR_OPTION];
|
||||||
|
|
||||||
const openSavedFiltersMenu = (event: any) => setSavedFiltersMenu(event.currentTarget);
|
const openSavedFiltersMenu = (event: any) => setSavedFiltersMenu(event.currentTarget);
|
||||||
const closeSavedFiltersMenu = () => setSavedFiltersMenu(null);
|
const closeSavedFiltersMenu = () => setSavedFiltersMenu(null);
|
||||||
@ -146,7 +150,6 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
|
|||||||
setSaveOptionsOpen(false);
|
setSaveOptionsOpen(false);
|
||||||
setPopupAlertContent(null);
|
setPopupAlertContent(null);
|
||||||
closeSavedFiltersMenu();
|
closeSavedFiltersMenu();
|
||||||
setSavedFilterNameInputValue(null);
|
|
||||||
setSaveFilterPopupOpen(true);
|
setSaveFilterPopupOpen(true);
|
||||||
setIsSaveFilterAs(false);
|
setIsSaveFilterAs(false);
|
||||||
setIsRenameFilter(false);
|
setIsRenameFilter(false);
|
||||||
@ -156,7 +159,7 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
|
|||||||
{
|
{
|
||||||
case SAVE_OPTION:
|
case SAVE_OPTION:
|
||||||
break;
|
break;
|
||||||
case SAVE_AS_OPTION:
|
case DUPLICATE_OPTION:
|
||||||
setIsSaveFilterAs(true);
|
setIsSaveFilterAs(true);
|
||||||
break;
|
break;
|
||||||
case CLEAR_OPTION:
|
case CLEAR_OPTION:
|
||||||
@ -165,6 +168,10 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
|
|||||||
navigate(metaData.getTablePathByName(tableMetaData.name));
|
navigate(metaData.getTablePathByName(tableMetaData.name));
|
||||||
break;
|
break;
|
||||||
case RENAME_OPTION:
|
case RENAME_OPTION:
|
||||||
|
if(currentSavedFilter != null)
|
||||||
|
{
|
||||||
|
setSavedFilterNameInputValue(currentSavedFilter.values.get("label"));
|
||||||
|
}
|
||||||
setIsRenameFilter(true);
|
setIsRenameFilter(true);
|
||||||
break;
|
break;
|
||||||
case DELETE_OPTION:
|
case DELETE_OPTION:
|
||||||
@ -322,9 +329,12 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
|
|||||||
return (savedFilters);
|
return (savedFilters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasStorePermission = metaData?.processes.has("storeSavedFilter");
|
||||||
|
const hasDeletePermission = metaData?.processes.has("deleteSavedFilter");
|
||||||
|
const hasQueryPermission = metaData?.processes.has("querySavedFilter");
|
||||||
|
|
||||||
const renderSavedFiltersMenu = tableMetaData && (
|
const renderSavedFiltersMenu = tableMetaData && (
|
||||||
<Menu
|
<Menu
|
||||||
sx={{width: "500px"}}
|
|
||||||
anchorEl={savedFiltersMenu}
|
anchorEl={savedFiltersMenu}
|
||||||
anchorOrigin={{
|
anchorOrigin={{
|
||||||
vertical: "bottom",
|
vertical: "bottom",
|
||||||
@ -338,10 +348,47 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
|
|||||||
onClose={closeSavedFiltersMenu}
|
onClose={closeSavedFiltersMenu}
|
||||||
keepMounted
|
keepMounted
|
||||||
>
|
>
|
||||||
|
<MenuItem sx={{width: "300px"}}><b>Filter Actions</b></MenuItem>
|
||||||
|
{
|
||||||
|
hasStorePermission &&
|
||||||
|
<MenuItem onClick={() => handleDropdownOptionClick(SAVE_OPTION)}>
|
||||||
|
<ListItemIcon><Icon>save</Icon></ListItemIcon>
|
||||||
|
Save...
|
||||||
|
</MenuItem>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
hasStorePermission &&
|
||||||
|
<MenuItem disabled={currentSavedFilter === null} onClick={() => handleDropdownOptionClick(RENAME_OPTION)}>
|
||||||
|
<ListItemIcon><Icon>edit</Icon></ListItemIcon>
|
||||||
|
Rename...
|
||||||
|
</MenuItem>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
hasStorePermission &&
|
||||||
|
<MenuItem disabled={currentSavedFilter === null} onClick={() => handleDropdownOptionClick(DUPLICATE_OPTION)}>
|
||||||
|
<ListItemIcon><Icon>content_copy</Icon></ListItemIcon>
|
||||||
|
Duplicate...
|
||||||
|
</MenuItem>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
hasDeletePermission &&
|
||||||
|
<MenuItem disabled={currentSavedFilter === null} onClick={() => handleDropdownOptionClick(DELETE_OPTION)}>
|
||||||
|
<ListItemIcon><Icon>delete</Icon></ListItemIcon>
|
||||||
|
Delete...
|
||||||
|
</MenuItem>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
<MenuItem disabled={currentSavedFilter === null} onClick={() => handleDropdownOptionClick(CLEAR_OPTION)}>
|
||||||
|
<ListItemIcon><Icon>clear</Icon></ListItemIcon>
|
||||||
|
Clear Current Filter
|
||||||
|
</MenuItem>
|
||||||
|
}
|
||||||
|
<Divider/>
|
||||||
|
<MenuItem><b>Your Filters</b></MenuItem>
|
||||||
{
|
{
|
||||||
savedFilters && savedFilters.length > 0 ? (
|
savedFilters && savedFilters.length > 0 ? (
|
||||||
savedFilters.map((record: QRecord, index: number) =>
|
savedFilters.map((record: QRecord, index: number) =>
|
||||||
<MenuItem key={`savedFiler-${index}`} onClick={() => handleSavedFilterRecordOnClick(record)}>
|
<MenuItem sx={{paddingLeft: "50px"}} key={`savedFiler-${index}`} onClick={() => handleSavedFilterRecordOnClick(record)}>
|
||||||
{record.values.get("label")}
|
{record.values.get("label")}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)
|
)
|
||||||
@ -354,38 +401,27 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
|
|||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const hasStorePermission = metaData?.processes.has("storeSavedFilter");
|
|
||||||
const hasDeletePermission = metaData?.processes.has("deleteSavedFilter");
|
|
||||||
const hasQueryPermission = metaData?.processes.has("querySavedFilter");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
hasQueryPermission && tableMetaData ? (
|
hasQueryPermission && tableMetaData ? (
|
||||||
<Box display="flex" flexGrow={1}>
|
<Box display="flex" flexGrow={1}>
|
||||||
<QSavedFiltersMenuButton isOpen={savedFiltersMenu} onClickHandler={openSavedFiltersMenu} />
|
<QSavedFiltersMenuButton isOpen={savedFiltersMenu} onClickHandler={openSavedFiltersMenu} />
|
||||||
{renderSavedFiltersMenu}
|
{renderSavedFiltersMenu}
|
||||||
<Box display="flex" justifyContent="flex-end" flexDirection="column">
|
<Box display="flex" justifyContent="center" flexDirection="column">
|
||||||
<Box pl={2} pr={2} sx={{display: "flex", alignItems: "center"}}>
|
<Box pl={2} pr={2} sx={{display: "flex", alignItems: "center"}}>
|
||||||
|
|
||||||
{
|
{
|
||||||
savedFiltersHaveLoaded && (
|
savedFiltersHaveLoaded && currentSavedFilter && (
|
||||||
currentSavedFilter ? (
|
<Typography mr={2} variant="h6">Current Filter:
|
||||||
<Typography mr={2} variant="h6">Current Filter:
|
<span style={{fontWeight: "initial"}}>
|
||||||
<span style={{fontWeight: "initial"}}>
|
{currentSavedFilter.values.get("label")}
|
||||||
{currentSavedFilter.values.get("label")}
|
{
|
||||||
{
|
filterIsModified && (
|
||||||
filterIsModified && (
|
<Tooltip sx={{cursor: "pointer"}} title={"The current has been modified, click \"Save...\" to save the changes."}>
|
||||||
<i> *</i>
|
<FiberManualRecord sx={{color: "orange", paddingLeft: "2px", paddingTop: "4px"}} />
|
||||||
|
</Tooltip>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
) : (
|
|
||||||
<Typography mr={2} variant="h6">
|
|
||||||
<span style={{fontWeight: "initial"}}> </span>
|
|
||||||
</Typography>
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</Box>
|
</Box>
|
||||||
@ -407,7 +443,7 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
|
|||||||
<Popper
|
<Popper
|
||||||
sx={{
|
sx={{
|
||||||
zIndex: 10,
|
zIndex: 10,
|
||||||
marginLeft: "175px !important"
|
marginLeft: "100px !important"
|
||||||
}}
|
}}
|
||||||
open={saveOptionsOpen}
|
open={saveOptionsOpen}
|
||||||
anchorEl={anchorRef.current}
|
anchorEl={anchorRef.current}
|
||||||
@ -428,7 +464,7 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
|
|||||||
<ClickAwayListener onClickAway={handleSaveOptionsMenuClose}>
|
<ClickAwayListener onClickAway={handleSaveOptionsMenuClose}>
|
||||||
<MenuList id="split-button-menu" autoFocusItem>
|
<MenuList id="split-button-menu" autoFocusItem>
|
||||||
{dropdownOptions.map((option, index) => (
|
{dropdownOptions.map((option, index) => (
|
||||||
(option === CLEAR_OPTION || ((option !== DELETE_OPTION || hasDeletePermission) && (option !== SAVE_AS_OPTION || hasStorePermission))) && (
|
(option === CLEAR_OPTION || ((option !== DELETE_OPTION || hasDeletePermission) && (option !== DUPLICATE_OPTION || hasStorePermission))) && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
key={option}
|
key={option}
|
||||||
onClick={() => handleDropdownOptionClick(option)}
|
onClick={() => handleDropdownOptionClick(option)}
|
||||||
@ -488,8 +524,13 @@ function SavedFilters({qController, metaData, tableMetaData, currentSavedFilter,
|
|||||||
placeholder="Filter Name"
|
placeholder="Filter Name"
|
||||||
label="Filter Name"
|
label="Filter Name"
|
||||||
inputProps={{width: "100%", maxLength: 100}}
|
inputProps={{width: "100%", maxLength: 100}}
|
||||||
|
value={savedFilterNameInputValue}
|
||||||
sx={{width: "100%"}}
|
sx={{width: "100%"}}
|
||||||
onChange={handleSaveFilterInputChange}
|
onChange={handleSaveFilterInputChange}
|
||||||
|
onFocus={event =>
|
||||||
|
{
|
||||||
|
event.target.select();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
):(
|
):(
|
||||||
|
@ -223,6 +223,11 @@ input[type="search"]::-webkit-search-results-decoration { display: none; }
|
|||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.MuiChip-root
|
||||||
|
{
|
||||||
|
padding-top: 1px !important;
|
||||||
|
}
|
||||||
|
|
||||||
#outlined-multiline-static
|
#outlined-multiline-static
|
||||||
{
|
{
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
|
Reference in New Issue
Block a user