Compare commits
5 Commits
f96fe1164b
...
89cf1fcd76
Author | SHA1 | Date |
---|---|---|
Tudor Stanciu | 89cf1fcd76 | |
Tudor Stanciu | 909f4df42a | |
Tudor Stanciu | 000faf1b7d | |
Tudor Stanciu | 94839a746b | |
Tudor Stanciu | 0814d09533 |
|
@ -1,2 +1,3 @@
|
||||||
- schimbare limba din setari
|
- schimbare limba din setari
|
||||||
- salvare configurari - pozitie toast
|
- salvare configurari - pozitie toast
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,37 @@
|
||||||
"English": "English",
|
"English": "English",
|
||||||
"Romanian": "Romanian"
|
"Romanian": "Romanian"
|
||||||
},
|
},
|
||||||
|
"Generic": {
|
||||||
|
"Table": {
|
||||||
|
"Body": {
|
||||||
|
"NoMatch": "Sorry, no matching records found"
|
||||||
|
},
|
||||||
|
"Filter": {
|
||||||
|
"All": "All",
|
||||||
|
"Reset": "Reset",
|
||||||
|
"Title": "FILTERS"
|
||||||
|
},
|
||||||
|
"Pagination": {
|
||||||
|
"DisplayRows": "of",
|
||||||
|
"Next": "Next page",
|
||||||
|
"Previous": "Previous page",
|
||||||
|
"RowsPerPage": "Rows per page"
|
||||||
|
},
|
||||||
|
"Toolbar": {
|
||||||
|
"DownloadCsv": "Download CSV",
|
||||||
|
"FilterTable": "Filter table",
|
||||||
|
"Print": "Print",
|
||||||
|
"Search": "Search",
|
||||||
|
"ViewColumns": "View columns"
|
||||||
|
},
|
||||||
|
"ViewColumns": {
|
||||||
|
"Title": "Show columns"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Edit": "Edit",
|
||||||
|
"More": "More",
|
||||||
|
"OpenInNewTab": "Open in new tab"
|
||||||
|
},
|
||||||
"Menu": {
|
"Menu": {
|
||||||
"Dashboard": "Dashboard",
|
"Dashboard": "Dashboard",
|
||||||
"Resources": "Resources",
|
"Resources": "Resources",
|
||||||
|
@ -37,5 +68,24 @@
|
||||||
"IncorrectCredentials": "Incorrect credentials.",
|
"IncorrectCredentials": "Incorrect credentials.",
|
||||||
"Hello": "Hi, {{username}}",
|
"Hello": "Hi, {{username}}",
|
||||||
"AuthenticationDate": "Authentication date"
|
"AuthenticationDate": "Authentication date"
|
||||||
|
},
|
||||||
|
"Resource": {
|
||||||
|
"Code": "Code",
|
||||||
|
"Name": "Name",
|
||||||
|
"Category": "Category",
|
||||||
|
"Secured": "Secured",
|
||||||
|
"List": {
|
||||||
|
"Title": "Resource management",
|
||||||
|
"SubTitle": "Resources",
|
||||||
|
"Filters": {
|
||||||
|
"Code": "Code contains: {{value}}",
|
||||||
|
"Name": "Name contains: {{value}}",
|
||||||
|
"Category": "Category: {{value}}"
|
||||||
|
},
|
||||||
|
"Actions": {
|
||||||
|
"CopyUrl": "Copy resource URL",
|
||||||
|
"LinkCopiedToClipboard": "The link has been copied to the clipboard."
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,37 @@
|
||||||
"English": "Engleză",
|
"English": "Engleză",
|
||||||
"Romanian": "Română"
|
"Romanian": "Română"
|
||||||
},
|
},
|
||||||
|
"Generic": {
|
||||||
|
"Table": {
|
||||||
|
"Body": {
|
||||||
|
"NoMatch": "Ne pare rău, nu s-au găsit înregistrări care se potrivesc"
|
||||||
|
},
|
||||||
|
"Filter": {
|
||||||
|
"All": "Toate",
|
||||||
|
"Reset": "Resetați",
|
||||||
|
"Title": "FILTRE"
|
||||||
|
},
|
||||||
|
"Pagination": {
|
||||||
|
"DisplayRows": "din",
|
||||||
|
"Next": "Pagina următoare",
|
||||||
|
"Previous": "Pagina anterioară",
|
||||||
|
"RowsPerPage": "Rânduri pe pagină"
|
||||||
|
},
|
||||||
|
"Toolbar": {
|
||||||
|
"DownloadCsv": "Descărcați CSV",
|
||||||
|
"FilterTable": "Filtrează tabel",
|
||||||
|
"Print": "Imprimare",
|
||||||
|
"Search": "Căutare",
|
||||||
|
"ViewColumns": "Vizualizați coloanele"
|
||||||
|
},
|
||||||
|
"ViewColumns": {
|
||||||
|
"Title": "Afișați coloanele"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Edit": "Editează",
|
||||||
|
"More": "Mai mult",
|
||||||
|
"OpenInNewTab": "Deschide într-un tab nou"
|
||||||
|
},
|
||||||
"Menu": {
|
"Menu": {
|
||||||
"Dashboard": "Dashboard",
|
"Dashboard": "Dashboard",
|
||||||
"Resources": "Resurse",
|
"Resources": "Resurse",
|
||||||
|
@ -28,5 +59,24 @@
|
||||||
"IncorrectCredentials": "Credențiale incorecte.",
|
"IncorrectCredentials": "Credențiale incorecte.",
|
||||||
"Hello": "Salut, {{username}}",
|
"Hello": "Salut, {{username}}",
|
||||||
"AuthenticationDate": "Momentul autentificării"
|
"AuthenticationDate": "Momentul autentificării"
|
||||||
|
},
|
||||||
|
"Resource": {
|
||||||
|
"Code": "Cod",
|
||||||
|
"Name": "Nume",
|
||||||
|
"Category": "Categorie",
|
||||||
|
"Secured": "Securizat",
|
||||||
|
"List": {
|
||||||
|
"Title": "Managementul resurselor",
|
||||||
|
"SubTitle": "Resurse",
|
||||||
|
"Filters": {
|
||||||
|
"Code": "Codul conține: {{value}}",
|
||||||
|
"Name": "Numele conține: {{value}}",
|
||||||
|
"Category": "Categorie: {{value}}"
|
||||||
|
},
|
||||||
|
"Actions": {
|
||||||
|
"CopyUrl": "Copiați adresa URL a resursei",
|
||||||
|
"LinkCopiedToClipboard": "Linkul a fost copiat în clipboard."
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,8 @@ import { get } from "../utils/axios";
|
||||||
|
|
||||||
const cdn = process.env.REACT_APP_CDN_URL;
|
const cdn = process.env.REACT_APP_CDN_URL;
|
||||||
const endpoints = {
|
const endpoints = {
|
||||||
mimeTypes: `${cdn}/admin/mime-types`
|
mimeTypes: `${cdn}/admin/mime-types`,
|
||||||
|
resourceCategories: `${cdn}/admin/resource-categories`
|
||||||
};
|
};
|
||||||
|
|
||||||
const useDictionariesApi = () => {
|
const useDictionariesApi = () => {
|
||||||
|
@ -18,8 +19,17 @@ const useDictionariesApi = () => {
|
||||||
[exec]
|
[exec]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const getResourceCategories = useCallback(
|
||||||
|
(options) => {
|
||||||
|
const promise = exec(() => get(endpoints.resourceCategories), options);
|
||||||
|
return promise;
|
||||||
|
},
|
||||||
|
[exec]
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getMimeTypes
|
getMimeTypes,
|
||||||
|
getResourceCategories
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import grey from "@material-ui/core/colors/grey";
|
||||||
|
import { Paper, makeStyles } from "@material-ui/core";
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
cover: {
|
||||||
|
width: "100%"
|
||||||
|
},
|
||||||
|
bar: {
|
||||||
|
backgroundColor: grey[200],
|
||||||
|
height: 10,
|
||||||
|
margin: 20,
|
||||||
|
"&:nth-child(2n)": {
|
||||||
|
marginRight: "20%"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
paper: {
|
||||||
|
padding: "10px",
|
||||||
|
borderRadius: "6px"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const useStyles = makeStyles(styles);
|
||||||
|
|
||||||
|
const LoadingText = ({ lines = 4, onPaper = false, ...props }) => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const loadingText = (
|
||||||
|
<div className={classes.cover} {...props}>
|
||||||
|
{[...Array(lines)].map((_e, i) => (
|
||||||
|
<div className={classes.bar} key={i}></div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (onPaper) {
|
||||||
|
return <Paper className={classes.paper}>{loadingText}</Paper>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadingText;
|
||||||
|
};
|
||||||
|
|
||||||
|
LoadingText.propTypes = {
|
||||||
|
lines: PropTypes.number,
|
||||||
|
onPaper: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoadingText;
|
|
@ -0,0 +1,3 @@
|
||||||
|
import LoadingText from "./LoadingContent/LoadingText";
|
||||||
|
|
||||||
|
export { LoadingText };
|
|
@ -1,6 +1,7 @@
|
||||||
const defaultResourcesFilters = Object.freeze({
|
const defaultResourcesFilters = Object.freeze({
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
|
loadedPages: null,
|
||||||
sortBy: null,
|
sortBy: null,
|
||||||
sortDirection: null,
|
sortDirection: null,
|
||||||
fullTextSearch: null,
|
fullTextSearch: null,
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import React, { forwardRef } from "react";
|
||||||
|
import { IconButton, Tooltip } from "@material-ui/core";
|
||||||
|
|
||||||
|
const ActionButton = forwardRef((props, _ref) => {
|
||||||
|
const { action, resource } = props;
|
||||||
|
return (
|
||||||
|
<Tooltip
|
||||||
|
id={`resource-${resource.resourceId}-${action.code}-tooltip`}
|
||||||
|
title={action.tooltip}
|
||||||
|
>
|
||||||
|
<span id={`resource-${resource.resourceId}-${action.code}`}>
|
||||||
|
<IconButton
|
||||||
|
id={`resource-${resource.resourceId}-${action.code}`}
|
||||||
|
size={"small"}
|
||||||
|
onClick={(event) => action.effect(event, resource)}
|
||||||
|
>
|
||||||
|
<action.icon />
|
||||||
|
</IconButton>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ActionButton;
|
|
@ -1,49 +1,122 @@
|
||||||
import React, { useState, useEffect, useMemo, useCallback } from "react";
|
import React, { useState, useEffect, useMemo, useCallback } from "react";
|
||||||
import { Grid, Checkbox, CircularProgress, FormLabel } from "@material-ui/core";
|
import { Checkbox, FormLabel } from "@material-ui/core";
|
||||||
import MUIDataTable, { debounceSearchRender } from "mui-datatables";
|
import MUIDataTable, { debounceSearchRender } from "mui-datatables";
|
||||||
|
import { LoadingText } from "../../../components";
|
||||||
import PageTitle from "../../../components/PageTitle";
|
import PageTitle from "../../../components/PageTitle";
|
||||||
import { useResourcesApi } from "../../../api";
|
import { useResourcesApi, useDictionariesApi } from "../../../api";
|
||||||
import { defaultResourcesFilters } from "../../../constants/resourcesConstants";
|
import { defaultResourcesFilters } from "../../../constants/resourcesConstants";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import ActionButton from "./ActionButton";
|
||||||
|
import SecondaryActionsGroup from "./SecondaryActionsGroup";
|
||||||
|
import {
|
||||||
|
EditOutlined,
|
||||||
|
FileCopyOutlined,
|
||||||
|
OpenInNewOutlined
|
||||||
|
} from "@material-ui/icons";
|
||||||
|
import { useToast } from "../../../context/ToastContext";
|
||||||
|
|
||||||
const __ROWS_PER_PAGE_OPTIONS = [10, 20, 50, 100];
|
const __ROWS_PER_PAGE_OPTIONS = [10, 20, 50, 100];
|
||||||
|
const __RESOURCE_NAME_MAX_LENGTH = 35;
|
||||||
|
|
||||||
const ResourcesContainer = () => {
|
const ResourcesContainer = () => {
|
||||||
const [state, setState] = useState({ loaded: false, loadedPages: null });
|
const [state, setState] = useState({
|
||||||
|
pageSize: 10,
|
||||||
|
totalCount: 0,
|
||||||
|
values: []
|
||||||
|
});
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
const [filters, setFilters] = useState({ ...defaultResourcesFilters });
|
const [filters, setFilters] = useState({ ...defaultResourcesFilters });
|
||||||
|
const [resourceCategories, setResourceCategories] = useState([]);
|
||||||
|
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { info } = useToast();
|
||||||
const { getResources } = useResourcesApi();
|
const { getResources } = useResourcesApi();
|
||||||
|
const { getResourceCategories } = useDictionariesApi();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.loadedPages && state.loadedPages.includes(filters.page)) return;
|
getResourceCategories().then((r) => setResourceCategories(r));
|
||||||
|
}, [getResourceCategories]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (filters.loadedPages && filters.loadedPages.includes(filters.page))
|
||||||
|
return;
|
||||||
|
|
||||||
|
setLoading(true);
|
||||||
getResources(filters, {
|
getResources(filters, {
|
||||||
onCompleted: (resources) => {
|
onCompleted: (resources) => {
|
||||||
const data = { ...resources, loaded: true };
|
|
||||||
setState((prev) => ({
|
setState((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
...data,
|
...resources,
|
||||||
values: prev?.values ? [...prev.values, ...data.values] : data.values,
|
values: filters.loadedPages
|
||||||
loadedPages: prev?.loadedPages
|
? [...prev.values, ...resources.values]
|
||||||
? [...prev.loadedPages, data.page]
|
: resources.values
|
||||||
: [data.page]
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
setFilters((prev) => ({
|
||||||
|
...prev,
|
||||||
|
loadedPages: prev?.loadedPages
|
||||||
|
? [...prev.loadedPages, resources.page]
|
||||||
|
: [resources.page]
|
||||||
|
}));
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [getResources, filters, state.loadedPages]);
|
}, [getResources, filters]);
|
||||||
|
|
||||||
|
const categoryFilterOptions = useMemo(
|
||||||
|
() => resourceCategories.map((z) => z.categoryName),
|
||||||
|
[resourceCategories]
|
||||||
|
);
|
||||||
|
|
||||||
|
const actions = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
code: "edit",
|
||||||
|
effect: () => alert("edit"),
|
||||||
|
icon: EditOutlined,
|
||||||
|
tooltip: t("Generic.Edit"),
|
||||||
|
top: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "copy-url",
|
||||||
|
effect: (_event, resource) => {
|
||||||
|
navigator.clipboard.writeText(resource.url);
|
||||||
|
info(t("Resource.List.Actions.LinkCopiedToClipboard"));
|
||||||
|
},
|
||||||
|
icon: FileCopyOutlined,
|
||||||
|
tooltip: t("Resource.List.Actions.CopyUrl"),
|
||||||
|
top: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "open-in-new-tab",
|
||||||
|
effect: (event, resource) => {
|
||||||
|
window.open(resource.url, "_blank");
|
||||||
|
event.preventDefault();
|
||||||
|
},
|
||||||
|
icon: OpenInNewOutlined,
|
||||||
|
tooltip: t("Generic.OpenInNewTab"),
|
||||||
|
top: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[t, info]
|
||||||
|
);
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
label: "Code",
|
label: t("Resource.Code"),
|
||||||
name: "resourceCode",
|
name: "resourceCode",
|
||||||
options: {
|
options: {
|
||||||
display: true,
|
display: true,
|
||||||
draggable: true,
|
draggable: true,
|
||||||
download: false,
|
download: true,
|
||||||
print: false,
|
print: false,
|
||||||
searchable: true,
|
searchable: true,
|
||||||
sort: true,
|
sort: true,
|
||||||
customFilterListOptions: {
|
customFilterListOptions: {
|
||||||
render: (v) => (v ? `Code contains: ${v}` : [])
|
render: (v) =>
|
||||||
|
v ? t("Resource.List.Filters.Code", { value: v }) : []
|
||||||
},
|
},
|
||||||
filter: true,
|
filter: true,
|
||||||
filterType: "textField",
|
filterType: "textField",
|
||||||
|
@ -55,17 +128,27 @@ const ResourcesContainer = () => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Name",
|
label: t("Resource.Name"),
|
||||||
name: "resourceName",
|
name: "resourceName",
|
||||||
options: {
|
options: {
|
||||||
display: true,
|
display: true,
|
||||||
draggable: true,
|
draggable: true,
|
||||||
download: false,
|
download: true,
|
||||||
print: false,
|
print: false,
|
||||||
searchable: true,
|
searchable: true,
|
||||||
sort: true,
|
sort: true,
|
||||||
|
customBodyRenderLite: (dataIndex, _rowIndex) => {
|
||||||
|
if (loading) return;
|
||||||
|
const value = state.values[dataIndex].resourceName;
|
||||||
|
const formattedValue =
|
||||||
|
value.length > __RESOURCE_NAME_MAX_LENGTH
|
||||||
|
? `${value.substring(0, __RESOURCE_NAME_MAX_LENGTH + 1)}[...]`
|
||||||
|
: value;
|
||||||
|
return formattedValue;
|
||||||
|
},
|
||||||
customFilterListOptions: {
|
customFilterListOptions: {
|
||||||
render: (v) => (v ? `Name contains: ${v}` : [])
|
render: (v) =>
|
||||||
|
v ? t("Resource.List.Filters.Name", { value: v }) : []
|
||||||
},
|
},
|
||||||
filter: true,
|
filter: true,
|
||||||
filterType: "textField",
|
filterType: "textField",
|
||||||
|
@ -77,31 +160,34 @@ const ResourcesContainer = () => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Category",
|
label: t("Resource.Category"),
|
||||||
name: "categoryId",
|
name: "categoryName",
|
||||||
options: {
|
options: {
|
||||||
display: true,
|
display: true,
|
||||||
draggable: true,
|
draggable: true,
|
||||||
download: false,
|
download: true,
|
||||||
print: false,
|
print: false,
|
||||||
searchable: true,
|
searchable: true,
|
||||||
sort: true,
|
sort: true,
|
||||||
filter: true,
|
filter: true,
|
||||||
|
customFilterListOptions: {
|
||||||
|
render: (v) => t("Resource.List.Filters.Category", { value: v })
|
||||||
|
},
|
||||||
filterType: "dropdown",
|
filterType: "dropdown",
|
||||||
filterOptions: {
|
filterOptions: {
|
||||||
|
names: categoryFilterOptions,
|
||||||
logic: (_prop, _filterValue, _row) => false
|
logic: (_prop, _filterValue, _row) => false
|
||||||
},
|
},
|
||||||
filterList: [],
|
|
||||||
hint: undefined
|
hint: undefined
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Secured",
|
label: t("Resource.Secured"),
|
||||||
name: "secured",
|
name: "secured",
|
||||||
options: {
|
options: {
|
||||||
display: true,
|
display: true,
|
||||||
draggable: true,
|
draggable: true,
|
||||||
download: false,
|
download: true,
|
||||||
print: false,
|
print: false,
|
||||||
searchable: true,
|
searchable: true,
|
||||||
sort: true,
|
sort: true,
|
||||||
|
@ -118,7 +204,7 @@ const ResourcesContainer = () => {
|
||||||
customFilterListOptions: {
|
customFilterListOptions: {
|
||||||
render: (v) => {
|
render: (v) => {
|
||||||
const checked = v[0];
|
const checked = v[0];
|
||||||
return checked ? <span>Secured</span> : [];
|
return checked ? <span>{t("Resource.Secured")}</span> : [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
filter: true,
|
filter: true,
|
||||||
|
@ -128,7 +214,7 @@ const ResourcesContainer = () => {
|
||||||
display: (filterList, onChange, index, column) => {
|
display: (filterList, onChange, index, column) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<FormLabel>Secured</FormLabel>
|
<FormLabel>{t("Resource.Secured")}</FormLabel>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
color="primary"
|
color="primary"
|
||||||
checked={filterList[index][0] || false}
|
checked={filterList[index][0] || false}
|
||||||
|
@ -141,67 +227,125 @@ const ResourcesContainer = () => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
filterList: undefined,
|
|
||||||
hint: undefined
|
hint: undefined
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "",
|
||||||
|
name: "actions",
|
||||||
|
options: {
|
||||||
|
customHeadLabelRender: (_options) => "",
|
||||||
|
display: true,
|
||||||
|
draggable: false,
|
||||||
|
download: false,
|
||||||
|
print: false,
|
||||||
|
searchable: false,
|
||||||
|
sort: false,
|
||||||
|
customBodyRenderLite: (dataIndex, _rowIndex) => {
|
||||||
|
if (loading) return;
|
||||||
|
const resource = state.values[dataIndex];
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{actions
|
||||||
|
.filter((a) => a.top === true)
|
||||||
|
.map((action) => (
|
||||||
|
<ActionButton
|
||||||
|
key={`resource-${resource.resourceId}-${action.code}`}
|
||||||
|
action={action}
|
||||||
|
resource={resource}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<SecondaryActionsGroup
|
||||||
|
resource={resource}
|
||||||
|
actions={actions.filter((a) => a.top === false)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
setCellProps: (_cellValue, _rowIndex, _columnIndex) => ({
|
||||||
|
style: {
|
||||||
|
paddingTop: "0px",
|
||||||
|
paddingBottom: "0px",
|
||||||
|
textAlign: "right"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
filter: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[]
|
[loading, state.values, categoryFilterOptions, t, actions]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleResetFilters = useCallback(() => {
|
const changeFilters = useCallback((obj) => {
|
||||||
setFilters((prev) => ({ ...prev, ...defaultResourcesFilters }));
|
const keys = Object.keys(obj);
|
||||||
}, [setFilters]);
|
const isPageChange = keys.length === 1 && keys[0] === "page";
|
||||||
|
if (!isPageChange) {
|
||||||
|
const { page, loadedPages } = defaultResourcesFilters;
|
||||||
|
obj = { ...obj, page, loadedPages };
|
||||||
|
}
|
||||||
|
|
||||||
|
setFilters((prev) => ({ ...prev, ...obj }));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getCategoryId = useCallback(
|
||||||
|
(name) => {
|
||||||
|
const category = resourceCategories.find((z) => z.categoryName === name);
|
||||||
|
return category?.categoryId;
|
||||||
|
},
|
||||||
|
[resourceCategories]
|
||||||
|
);
|
||||||
|
|
||||||
const handleFilterChange = useCallback(
|
const handleFilterChange = useCallback(
|
||||||
(changedColumn, filterList, type, changedColumnIndex, displayData) => {
|
(changedColumn, filterList, type, changedColumnIndex, _displayData) => {
|
||||||
if (type === "reset") {
|
if (type === "reset") {
|
||||||
handleResetFilters();
|
changeFilters(defaultResourcesFilters);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterValue = filterList[changedColumnIndex][0];
|
const filterValue = filterList[changedColumnIndex][0];
|
||||||
setFilters((prev) => ({
|
|
||||||
...prev,
|
if (changedColumn === "categoryName") {
|
||||||
[changedColumn]: filterValue
|
const categoryId = filterValue
|
||||||
}));
|
? getCategoryId(filterValue)
|
||||||
|
: filterValue;
|
||||||
|
changeFilters({ categoryId });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
changeFilters({ [changedColumn]: filterValue });
|
||||||
},
|
},
|
||||||
[handleResetFilters]
|
[changeFilters, getCategoryId]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageTitle title="ResourcesX" />
|
<PageTitle title={t("Resource.List.Title")} />
|
||||||
{state.loaded === false ? (
|
|
||||||
<CircularProgress size={26} />
|
|
||||||
) : (
|
|
||||||
<MUIDataTable
|
<MUIDataTable
|
||||||
title="Resources"
|
title={t("Resource.List.SubTitle")}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={state.values ?? []}
|
data={state.values}
|
||||||
options={{
|
options={{
|
||||||
filterType: "textField",
|
filterType: "textField",
|
||||||
expandableRows: false,
|
expandableRows: false,
|
||||||
print: false,
|
print: false,
|
||||||
selectableRows: "none",
|
selectableRows: "none",
|
||||||
|
page: filters.page - 1,
|
||||||
rowsPerPage: state.pageSize,
|
rowsPerPage: state.pageSize,
|
||||||
rowsPerPageOptions: __ROWS_PER_PAGE_OPTIONS,
|
rowsPerPageOptions: __ROWS_PER_PAGE_OPTIONS,
|
||||||
count: state.totalCount,
|
count: state.totalCount,
|
||||||
customSearchRender: debounceSearchRender(500),
|
customSearchRender: debounceSearchRender(500),
|
||||||
onChangePage: (currentPage) => {
|
onChangePage: (currentPage) =>
|
||||||
setFilters((prev) => ({ ...prev, page: currentPage + 1 }));
|
changeFilters({ page: currentPage + 1 }),
|
||||||
},
|
onChangeRowsPerPage: (numberOfRows) =>
|
||||||
onChangeRowsPerPage: (numberOfRows) => {
|
changeFilters({ pageSize: numberOfRows }),
|
||||||
setFilters((prev) => ({ ...prev, pageSize: numberOfRows }));
|
|
||||||
},
|
|
||||||
onColumnSortChange: (changedColumn, direction) =>
|
onColumnSortChange: (changedColumn, direction) =>
|
||||||
setFilters((prev) => ({
|
changeFilters({
|
||||||
...prev,
|
|
||||||
sortBy: changedColumn,
|
sortBy: changedColumn,
|
||||||
sortDirection: direction
|
sortDirection: direction
|
||||||
})),
|
}),
|
||||||
onFilterChange: handleFilterChange,
|
onFilterChange: handleFilterChange,
|
||||||
onSearchChange: (text) =>
|
onSearchChange: (text) => changeFilters({ fullTextSearch: text }),
|
||||||
setFilters((prev) => ({ ...prev, fullTextSearch: text })),
|
|
||||||
customSort: (data) => data,
|
customSort: (data) => data,
|
||||||
customSearch: () => true,
|
customSearch: () => true,
|
||||||
setFilterChipProps: (_colIndex, _colName, _data) => {
|
setFilterChipProps: (_colIndex, _colName, _data) => {
|
||||||
|
@ -209,10 +353,39 @@ const ResourcesContainer = () => {
|
||||||
color: "primary",
|
color: "primary",
|
||||||
variant: "outlined"
|
variant: "outlined"
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
textLabels: {
|
||||||
|
body: {
|
||||||
|
noMatch: loading ? (
|
||||||
|
<LoadingText lines={15} />
|
||||||
|
) : (
|
||||||
|
<>{t("Generic.Table.Body.NoMatch")}</>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
filter: {
|
||||||
|
all: t("Generic.Table.Filter.All"),
|
||||||
|
reset: t("Generic.Table.Filter.Reset"),
|
||||||
|
title: t("Generic.Table.Filter.Title")
|
||||||
|
},
|
||||||
|
pagination: {
|
||||||
|
displayRows: t("Generic.Table.Pagination.DisplayRows"),
|
||||||
|
next: t("Generic.Table.Pagination.Next"),
|
||||||
|
previous: t("Generic.Table.Pagination.Previous"),
|
||||||
|
rowsPerPage: t("Generic.Table.Pagination.RowsPerPage")
|
||||||
|
},
|
||||||
|
toolbar: {
|
||||||
|
downloadCsv: t("Generic.Table.Toolbar.DownloadCsv"),
|
||||||
|
filterTable: t("Generic.Table.Toolbar.FilterTable"),
|
||||||
|
print: t("Generic.Table.Toolbar.Print"),
|
||||||
|
search: t("Generic.Table.Toolbar.Search"),
|
||||||
|
viewColumns: t("Generic.Table.Toolbar.ViewColumns")
|
||||||
|
},
|
||||||
|
viewColumns: {
|
||||||
|
title: t("Generic.Table.ViewColumns.Title")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { Menu } from "@material-ui/core";
|
||||||
|
import ActionButton from "./ActionButton";
|
||||||
|
import { MoreHorizOutlined } from "@material-ui/icons";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
const SecondaryActionsGroup = ({ resource, actions }) => {
|
||||||
|
const [menuAnchor, setMenuAnchor] = useState(null);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ActionButton
|
||||||
|
key={`resource-${resource.resourceId}-more`}
|
||||||
|
action={{
|
||||||
|
code: "more",
|
||||||
|
effect: (event) => setMenuAnchor(event.currentTarget),
|
||||||
|
icon: MoreHorizOutlined,
|
||||||
|
tooltip: t("Generic.More"),
|
||||||
|
top: true
|
||||||
|
}}
|
||||||
|
resource={resource}
|
||||||
|
/>
|
||||||
|
<Menu
|
||||||
|
id={`resource-${resource.resourceId}-secondary-actions-menu`}
|
||||||
|
key={`resource-${resource.resourceId}-secondary-actions-menu`}
|
||||||
|
anchorEl={menuAnchor}
|
||||||
|
open={Boolean(menuAnchor)}
|
||||||
|
onClose={() => setMenuAnchor(null)}
|
||||||
|
>
|
||||||
|
{actions.map((action) => (
|
||||||
|
<ActionButton
|
||||||
|
key={`resource-${resource.resourceId}-${action.code}`}
|
||||||
|
action={action}
|
||||||
|
resource={resource}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Menu>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SecondaryActionsGroup;
|
Loading…
Reference in New Issue