mirror of
https://github.com/hexastack/hexabot
synced 2025-06-26 18:27:28 +00:00
fix(frontend): align data grid toggle action
This commit is contained in:
parent
b735d5ebd1
commit
357da9baf2
@ -42,7 +42,6 @@ export class UserStub extends BaseSchema {
|
|||||||
|
|
||||||
@Prop({
|
@Prop({
|
||||||
type: String,
|
type: String,
|
||||||
unique: true,
|
|
||||||
required: true,
|
required: true,
|
||||||
})
|
})
|
||||||
password: string;
|
password: string;
|
||||||
|
@ -6,11 +6,12 @@
|
|||||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { styled } from "@mui/material";
|
import { useTheme } from "@mui/material";
|
||||||
import {
|
import {
|
||||||
DataGridProps,
|
DataGridProps,
|
||||||
gridClasses,
|
gridClasses,
|
||||||
GridColDef,
|
GridColDef,
|
||||||
|
GridValidRowModel,
|
||||||
DataGrid as MuiDataGrid,
|
DataGrid as MuiDataGrid,
|
||||||
} from "@mui/x-data-grid";
|
} from "@mui/x-data-grid";
|
||||||
|
|
||||||
@ -18,22 +19,34 @@ import { renderHeader } from "./columns/renderHeader";
|
|||||||
import { styledPaginationSlots } from "./DataGridStyledPagination";
|
import { styledPaginationSlots } from "./DataGridStyledPagination";
|
||||||
import { NoDataOverlay } from "./NoDataOverlay";
|
import { NoDataOverlay } from "./NoDataOverlay";
|
||||||
|
|
||||||
const StyledDataGrid = styled(MuiDataGrid)(({ theme }) => ({
|
export const StyledDataGrid = <T extends GridValidRowModel = any>(
|
||||||
"& .MuiDataGrid-overlayWrapper": {
|
props: DataGridProps<T>,
|
||||||
height: "fit-content",
|
) => {
|
||||||
},
|
const theme = useTheme();
|
||||||
|
const { sx, ...otherProps } = props;
|
||||||
|
|
||||||
[`& .${gridClasses.row}`]: {
|
return (
|
||||||
"&:hover": {
|
<MuiDataGrid
|
||||||
backgroundColor: theme.palette.background.default,
|
{...otherProps}
|
||||||
"@media (hover: none)": {
|
sx={{
|
||||||
backgroundColor: theme.palette.background.default,
|
"& .MuiDataGrid-overlayWrapper": {
|
||||||
},
|
height: "fit-content",
|
||||||
},
|
},
|
||||||
},
|
[`& .${gridClasses.row}`]: {
|
||||||
}));
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.background.default,
|
||||||
|
"@media (hover: none)": {
|
||||||
|
backgroundColor: theme.palette.background.default,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...sx,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const DataGrid = ({
|
export const DataGrid = <T extends GridValidRowModel = any>({
|
||||||
columns,
|
columns,
|
||||||
rows = [],
|
rows = [],
|
||||||
autoHeight = true,
|
autoHeight = true,
|
||||||
@ -46,8 +59,8 @@ export const DataGrid = ({
|
|||||||
showColumnVerticalBorder = false,
|
showColumnVerticalBorder = false,
|
||||||
sx = { border: "none" },
|
sx = { border: "none" },
|
||||||
...rest
|
...rest
|
||||||
}: DataGridProps) => {
|
}: DataGridProps<T>) => {
|
||||||
const styledColumns: GridColDef[] = columns.map((col) => ({
|
const styledColumns: GridColDef<T>[] = columns.map((col) => ({
|
||||||
disableColumnMenu: true,
|
disableColumnMenu: true,
|
||||||
renderHeader,
|
renderHeader,
|
||||||
headerAlign: "left",
|
headerAlign: "left",
|
||||||
@ -56,7 +69,7 @@ export const DataGrid = ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledDataGrid
|
<StyledDataGrid<T>
|
||||||
autoHeight={autoHeight}
|
autoHeight={autoHeight}
|
||||||
disableRowSelectionOnClick={disableRowSelectionOnClick}
|
disableRowSelectionOnClick={disableRowSelectionOnClick}
|
||||||
slots={slots}
|
slots={slots}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import { faAlignLeft } from "@fortawesome/free-solid-svg-icons";
|
import { faAlignLeft } from "@fortawesome/free-solid-svg-icons";
|
||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
||||||
import { Button, Chip, Grid, Paper, Typography } from "@mui/material";
|
import { Button, Chip, Grid, Paper, Switch, Typography } from "@mui/material";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@ -24,13 +24,14 @@ import { renderHeader } from "@/app-components/tables/columns/renderHeader";
|
|||||||
import { DataGrid } from "@/app-components/tables/DataGrid";
|
import { DataGrid } from "@/app-components/tables/DataGrid";
|
||||||
import { useDelete } from "@/hooks/crud/useDelete";
|
import { useDelete } from "@/hooks/crud/useDelete";
|
||||||
import { useFind } from "@/hooks/crud/useFind";
|
import { useFind } from "@/hooks/crud/useFind";
|
||||||
import { useGet } from "@/hooks/crud/useGet";
|
import { useGet, useGetFromCache } from "@/hooks/crud/useGet";
|
||||||
|
import { useUpdate } from "@/hooks/crud/useUpdate";
|
||||||
import { getDisplayDialogs, useDialog } from "@/hooks/useDialog";
|
import { getDisplayDialogs, useDialog } from "@/hooks/useDialog";
|
||||||
import { useHasPermission } from "@/hooks/useHasPermission";
|
import { useHasPermission } from "@/hooks/useHasPermission";
|
||||||
import { useSearch } from "@/hooks/useSearch";
|
import { useSearch } from "@/hooks/useSearch";
|
||||||
import { useToast } from "@/hooks/useToast";
|
import { useToast } from "@/hooks/useToast";
|
||||||
import { PageHeader } from "@/layout/content/PageHeader";
|
import { PageHeader } from "@/layout/content/PageHeader";
|
||||||
import { EntityType } from "@/services/types";
|
import { EntityType, Format } from "@/services/types";
|
||||||
import { IContentType } from "@/types/content-type.types";
|
import { IContentType } from "@/types/content-type.types";
|
||||||
import { IContent } from "@/types/content.types";
|
import { IContent } from "@/types/content.types";
|
||||||
import { PermissionAction } from "@/types/permission.types";
|
import { PermissionAction } from "@/types/permission.types";
|
||||||
@ -62,17 +63,26 @@ export const Contents = () => {
|
|||||||
entity: EntityType.CONTENT_TYPE,
|
entity: EntityType.CONTENT_TYPE,
|
||||||
});
|
});
|
||||||
const { dataGridProps } = useFind(
|
const { dataGridProps } = useFind(
|
||||||
{ entity: EntityType.CONTENT },
|
{ entity: EntityType.CONTENT, format: Format.FULL },
|
||||||
{
|
{
|
||||||
params: searchPayload,
|
params: searchPayload,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
const { mutateAsync: updateContent } = useUpdate(EntityType.CONTENT, {
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(error.message || t("message.internal_server_error"));
|
||||||
|
},
|
||||||
|
onSuccess() {
|
||||||
|
toast.success(t("message.success_save"));
|
||||||
|
},
|
||||||
|
});
|
||||||
const { mutateAsync: deleteContent } = useDelete(EntityType.CONTENT, {
|
const { mutateAsync: deleteContent } = useDelete(EntityType.CONTENT, {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
deleteDialogCtl.closeDialog();
|
deleteDialogCtl.closeDialog();
|
||||||
toast.success(t("message.item_delete_success"));
|
toast.success(t("message.item_delete_success"));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const getEntityFromCache = useGetFromCache(EntityType.CONTENT_TYPE);
|
||||||
const actionColumns = useActionColumns<IContent>(
|
const actionColumns = useActionColumns<IContent>(
|
||||||
EntityType.CONTENT,
|
EntityType.CONTENT,
|
||||||
[
|
[
|
||||||
@ -108,7 +118,7 @@ export const Contents = () => {
|
|||||||
|
|
||||||
<PageHeader
|
<PageHeader
|
||||||
icon={faAlignLeft}
|
icon={faAlignLeft}
|
||||||
chip={<Chip label={data?.name} variant="title" />}
|
chip={<Chip label={data?.name} size="medium" variant="title" />}
|
||||||
title={t("title.content")}
|
title={t("title.content")}
|
||||||
>
|
>
|
||||||
<Grid justifyContent="flex-end" gap={1} container alignItems="center">
|
<Grid justifyContent="flex-end" gap={1} container alignItems="center">
|
||||||
@ -143,7 +153,7 @@ export const Contents = () => {
|
|||||||
|
|
||||||
<Grid padding={2} container>
|
<Grid padding={2} container>
|
||||||
<Grid item width="100%">
|
<Grid item width="100%">
|
||||||
<DataGrid
|
<DataGrid<IContent>
|
||||||
{...dataGridProps}
|
{...dataGridProps}
|
||||||
disableColumnFilter
|
disableColumnFilter
|
||||||
showCellVerticalBorder={false}
|
showCellVerticalBorder={false}
|
||||||
@ -155,25 +165,39 @@ export const Contents = () => {
|
|||||||
field: "entity",
|
field: "entity",
|
||||||
headerName: t("label.entity"),
|
headerName: t("label.entity"),
|
||||||
flex: 1,
|
flex: 1,
|
||||||
valueGetter: (row) => row["name"],
|
valueGetter: (row: IContent) => {
|
||||||
|
const contentType = getEntityFromCache(row.id);
|
||||||
|
|
||||||
|
return contentType?.name;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
maxWidth: 120,
|
||||||
field: "status",
|
field: "status",
|
||||||
headerName: t("label.status"),
|
headerName: t("label.status"),
|
||||||
resizable: false,
|
disableColumnMenu: true,
|
||||||
|
renderHeader,
|
||||||
|
headerAlign: "left",
|
||||||
renderCell: (params) => (
|
renderCell: (params) => (
|
||||||
<Grid container>
|
<Switch
|
||||||
<Grid item xs={12}>
|
checked={params.value}
|
||||||
<Chip
|
color="primary"
|
||||||
label={t(
|
inputProps={{ "aria-label": "primary checkbox" }}
|
||||||
params.row.status
|
disabled={
|
||||||
? "label.enabled"
|
!hasPermission(
|
||||||
: "label.disabled",
|
EntityType.CONTENT,
|
||||||
)}
|
PermissionAction.UPDATE,
|
||||||
variant={params.row.status ? "enabled" : "disabled"}
|
)
|
||||||
/>
|
}
|
||||||
</Grid>
|
onChange={() => {
|
||||||
</Grid>
|
updateContent({
|
||||||
|
id: params.row.id,
|
||||||
|
params: {
|
||||||
|
status: !params.row.status,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -107,6 +107,9 @@ export const ContextVars = () => {
|
|||||||
checked={params.value}
|
checked={params.value}
|
||||||
color="primary"
|
color="primary"
|
||||||
inputProps={{ "aria-label": "primary checkbox" }}
|
inputProps={{ "aria-label": "primary checkbox" }}
|
||||||
|
disabled={
|
||||||
|
!hasPermission(EntityType.CONTEXT_VAR, PermissionAction.UPDATE)
|
||||||
|
}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
updateContextVar({
|
updateContextVar({
|
||||||
id: params.row.id,
|
id: params.row.id,
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import { Flag } from "@mui/icons-material";
|
import { Flag } from "@mui/icons-material";
|
||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
import { Button, Grid, Paper } from "@mui/material";
|
import { Button, Grid, Paper, Switch } from "@mui/material";
|
||||||
import { GridColDef } from "@mui/x-data-grid";
|
import { GridColDef } from "@mui/x-data-grid";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useQueryClient } from "react-query";
|
import { useQueryClient } from "react-query";
|
||||||
@ -92,13 +92,6 @@ export const Languages = () => {
|
|||||||
const actionColumns = useActionColumns<ILanguage>(
|
const actionColumns = useActionColumns<ILanguage>(
|
||||||
EntityType.LANGUAGE,
|
EntityType.LANGUAGE,
|
||||||
[
|
[
|
||||||
{
|
|
||||||
label: ActionColumnLabel.Toggle,
|
|
||||||
action: (row) => toggleDefault(row),
|
|
||||||
requires: [PermissionAction.UPDATE],
|
|
||||||
getState: (row) => row.isDefault,
|
|
||||||
helperText: t("button.mark_as_default"),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: ActionColumnLabel.Edit,
|
label: ActionColumnLabel.Edit,
|
||||||
action: (row) => editDialogCtl.openDialog(row),
|
action: (row) => editDialogCtl.openDialog(row),
|
||||||
@ -131,15 +124,6 @@ export const Languages = () => {
|
|||||||
renderHeader,
|
renderHeader,
|
||||||
headerAlign: "left",
|
headerAlign: "left",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
flex: 1,
|
|
||||||
field: "isDefault",
|
|
||||||
headerName: t("label.is_default"),
|
|
||||||
disableColumnMenu: true,
|
|
||||||
renderHeader,
|
|
||||||
headerAlign: "left",
|
|
||||||
valueGetter: (value) => (value ? t("label.yes") : t("label.no")),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
field: "isRTL",
|
field: "isRTL",
|
||||||
@ -149,6 +133,27 @@ export const Languages = () => {
|
|||||||
headerAlign: "left",
|
headerAlign: "left",
|
||||||
valueGetter: (value) => (value ? t("label.yes") : t("label.no")),
|
valueGetter: (value) => (value ? t("label.yes") : t("label.no")),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
maxWidth: 120,
|
||||||
|
field: "isDefault",
|
||||||
|
headerName: t("label.is_default"),
|
||||||
|
disableColumnMenu: true,
|
||||||
|
renderHeader,
|
||||||
|
headerAlign: "left",
|
||||||
|
renderCell: (params) => (
|
||||||
|
<Switch
|
||||||
|
checked={params.value}
|
||||||
|
color="primary"
|
||||||
|
inputProps={{ "aria-label": "primary checkbox" }}
|
||||||
|
disabled={
|
||||||
|
!hasPermission(EntityType.LANGUAGE, PermissionAction.UPDATE)
|
||||||
|
}
|
||||||
|
onChange={() => {
|
||||||
|
toggleDefault(params.row);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
field: "createdAt",
|
field: "createdAt",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import { faUsers } from "@fortawesome/free-solid-svg-icons";
|
import { faUsers } from "@fortawesome/free-solid-svg-icons";
|
||||||
import PersonAddAlt1Icon from "@mui/icons-material/PersonAddAlt1";
|
import PersonAddAlt1Icon from "@mui/icons-material/PersonAddAlt1";
|
||||||
import { Button, Grid, Paper } from "@mui/material";
|
import { Button, Grid, Paper, Switch } from "@mui/material";
|
||||||
import { GridColDef } from "@mui/x-data-grid";
|
import { GridColDef } from "@mui/x-data-grid";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
@ -23,6 +23,7 @@ import { buildRenderPicture } from "@/app-components/tables/columns/renderPictur
|
|||||||
import { DataGrid } from "@/app-components/tables/DataGrid";
|
import { DataGrid } from "@/app-components/tables/DataGrid";
|
||||||
import { useFind } from "@/hooks/crud/useFind";
|
import { useFind } from "@/hooks/crud/useFind";
|
||||||
import { useUpdate } from "@/hooks/crud/useUpdate";
|
import { useUpdate } from "@/hooks/crud/useUpdate";
|
||||||
|
import { useAuth } from "@/hooks/useAuth";
|
||||||
import { useConfig } from "@/hooks/useConfig";
|
import { useConfig } from "@/hooks/useConfig";
|
||||||
import { getDisplayDialogs, useDialog } from "@/hooks/useDialog";
|
import { getDisplayDialogs, useDialog } from "@/hooks/useDialog";
|
||||||
import { useHasPermission } from "@/hooks/useHasPermission";
|
import { useHasPermission } from "@/hooks/useHasPermission";
|
||||||
@ -42,6 +43,7 @@ export const Users = () => {
|
|||||||
const { ssoEnabled } = useConfig();
|
const { ssoEnabled } = useConfig();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
const { user } = useAuth();
|
||||||
const { mutateAsync: updateUser } = useUpdate(EntityType.USER, {
|
const { mutateAsync: updateUser } = useUpdate(EntityType.USER, {
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
toast.error(error.message || t("message.internal_server_error"));
|
toast.error(error.message || t("message.internal_server_error"));
|
||||||
@ -136,33 +138,29 @@ export const Users = () => {
|
|||||||
maxWidth: 120,
|
maxWidth: 120,
|
||||||
field: "state",
|
field: "state",
|
||||||
headerName: t("label.status"),
|
headerName: t("label.status"),
|
||||||
resizable: false,
|
|
||||||
disableColumnMenu: true,
|
disableColumnMenu: true,
|
||||||
renderCell: (params) => (
|
|
||||||
<Grid justifyContent="center" alignItems="center">
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
color={params.row.state ? "success" : "error"}
|
|
||||||
sx={{
|
|
||||||
paddingX: 2,
|
|
||||||
paddingY: 1,
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
updateUser({
|
|
||||||
id: params.row.id,
|
|
||||||
params: {
|
|
||||||
state: !params.row.state,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
disabled={ssoEnabled}
|
|
||||||
>
|
|
||||||
{t(params.row.state ? "label.enabled" : "label.disabled")}
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
),
|
|
||||||
headerAlign: "center",
|
|
||||||
renderHeader,
|
renderHeader,
|
||||||
|
headerAlign: "left",
|
||||||
|
renderCell: (params) => (
|
||||||
|
<Switch
|
||||||
|
checked={params.value}
|
||||||
|
color="primary"
|
||||||
|
inputProps={{ "aria-label": "primary checkbox" }}
|
||||||
|
disabled={
|
||||||
|
params.row.id === user?.id ||
|
||||||
|
ssoEnabled ||
|
||||||
|
!hasPermission(EntityType.USER, PermissionAction.UPDATE)
|
||||||
|
}
|
||||||
|
onChange={() => {
|
||||||
|
updateUser({
|
||||||
|
id: params.row.id,
|
||||||
|
params: {
|
||||||
|
state: !params.row.state,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
|
Loading…
Reference in New Issue
Block a user