mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
49
Makefile
49
Makefile
@@ -19,7 +19,7 @@ C = $(words $N)$(eval N := x $N)
|
|||||||
ECHO = python3 $(I)/scripts/echo_progress.py --stepno=$C --nsteps=$T
|
ECHO = python3 $(I)/scripts/echo_progress.py --stepno=$C --nsteps=$T
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# determine number of parallel compiles based on OS
|
# Optimize parallel build configuration
|
||||||
UNAME_S := $(shell uname -s)
|
UNAME_S := $(shell uname -s)
|
||||||
ifeq ($(UNAME_S),Linux)
|
ifeq ($(UNAME_S),Linux)
|
||||||
EXTRA_CPPFLAGS = -D LINUX
|
EXTRA_CPPFLAGS = -D LINUX
|
||||||
@@ -29,7 +29,9 @@ ifeq ($(UNAME_S),Darwin)
|
|||||||
EXTRA_CPPFLAGS = -D OSX -Wno-tautological-constant-out-of-range-compare
|
EXTRA_CPPFLAGS = -D OSX -Wno-tautological-constant-out-of-range-compare
|
||||||
JOBS ?= $(shell sysctl -n hw.ncpu)
|
JOBS ?= $(shell sysctl -n hw.ncpu)
|
||||||
endif
|
endif
|
||||||
MAKEFLAGS += -j $(JOBS) -l $(JOBS)
|
|
||||||
|
# Set optimal parallel build settings
|
||||||
|
MAKEFLAGS += -j$(JOBS) -l$(shell echo $$(($(JOBS) * 2)))
|
||||||
|
|
||||||
# $(info Number of jobs: $(JOBS))
|
# $(info Number of jobs: $(JOBS))
|
||||||
|
|
||||||
@@ -72,16 +74,21 @@ DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DE
|
|||||||
OUTPUT := $(CURDIR)/$(TARGET)
|
OUTPUT := $(CURDIR)/$(TARGET)
|
||||||
SYMBOLS := $(CURDIR)/$(BUILD)/$(TARGET).out
|
SYMBOLS := $(CURDIR)/$(BUILD)/$(TARGET).out
|
||||||
|
|
||||||
CSOURCES := $(foreach dir,$(SOURCES),$(wildcard $(dir)/*.c))
|
# Optimize source discovery - use shell find for better performance
|
||||||
CXXSOURCES := $(foreach dir,$(SOURCES),$(wildcard $(dir)/*.cpp))
|
CSOURCES := $(shell find $(SOURCES) -name "*.c" 2>/dev/null)
|
||||||
|
CXXSOURCES := $(shell find $(SOURCES) -name "*.cpp" 2>/dev/null)
|
||||||
|
|
||||||
OBJS := $(patsubst %,$(BUILD)/%.o,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)) )
|
OBJS := $(patsubst %,$(BUILD)/%.o,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)))
|
||||||
DEPS := $(patsubst %,$(BUILD)/%.d,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)) )
|
DEPS := $(patsubst %,$(BUILD)/%.d,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)))
|
||||||
|
|
||||||
INCLUDE += $(addprefix -I,$(foreach dir,$(INCLUDES), $(wildcard $(dir))))
|
# Optimize include path discovery
|
||||||
INCLUDE += $(addprefix -I,$(foreach dir,$(LIBRARIES),$(wildcard $(dir)/include)))
|
INCLUDE_DIRS := $(shell find $(INCLUDES) -type d 2>/dev/null)
|
||||||
|
LIBRARY_INCLUDES := $(shell find $(LIBRARIES) -name "include" -type d 2>/dev/null)
|
||||||
|
INCLUDE += $(addprefix -I,$(INCLUDE_DIRS) $(LIBRARY_INCLUDES))
|
||||||
|
|
||||||
LDLIBS += $(addprefix -L,$(foreach dir,$(LIBRARIES),$(wildcard $(dir)/lib)))
|
# Optimize library path discovery
|
||||||
|
LIBRARY_DIRS := $(shell find $(LIBRARIES) -name "lib" -type d 2>/dev/null)
|
||||||
|
LDLIBS += $(addprefix -L,$(LIBRARY_DIRS))
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Compiler & Linker
|
# Compiler & Linker
|
||||||
@@ -99,9 +106,11 @@ CXX := /usr/bin/g++
|
|||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
CPPFLAGS += $(DEFINES) $(DEFAULTS) $(INCLUDE)
|
CPPFLAGS += $(DEFINES) $(DEFAULTS) $(INCLUDE)
|
||||||
CPPFLAGS += -ggdb -g3 -MMD
|
CPPFLAGS += -ggdb -g3 -MMD
|
||||||
CPPFLAGS += -flto=auto -fno-lto
|
CPPFLAGS += -flto=auto
|
||||||
CPPFLAGS += -Wall -Wextra -Werror -Wswitch-enum
|
CPPFLAGS += -Wall -Wextra -Werror -Wswitch-enum
|
||||||
CPPFLAGS += -Wno-unused-parameter -Wno-missing-braces -Wno-vla-cxx-extension
|
CPPFLAGS += -Wno-unused-parameter -Wno-missing-braces -Wno-vla-cxx-extension
|
||||||
|
CPPFLAGS += -ffunction-sections -fdata-sections -fno-exceptions -fno-rtti -fno-threadsafe-statics
|
||||||
|
CPPFLAGS += -Os -DNDEBUG
|
||||||
|
|
||||||
CPPFLAGS += $(EXTRA_CPPFLAGS)
|
CPPFLAGS += $(EXTRA_CPPFLAGS)
|
||||||
|
|
||||||
@@ -122,7 +131,8 @@ else
|
|||||||
LD := $(CXX)
|
LD := $(CXX)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#DEPFLAGS += -MF $(BUILD)/$*.d
|
# Dependency file generation
|
||||||
|
DEPFLAGS += -MF $(BUILD)/$*.d -MT $@
|
||||||
|
|
||||||
LINK.o = $(LD) $(LDFLAGS) $(LDLIBS) $^ -o $@
|
LINK.o = $(LD) $(LDFLAGS) $(LDLIBS) $^ -o $@
|
||||||
COMPILE.c = $(CC) $(C_STANDARD) $(CFLAGS) $(DEPFLAGS) -c $< -o $@
|
COMPILE.c = $(CC) $(C_STANDARD) $(CFLAGS) $(DEPFLAGS) -c $< -o $@
|
||||||
@@ -139,7 +149,10 @@ COMPILE.cpp = $(CXX) $(CXX_STANDARD) $(CXXFLAGS) $(DEPFLAGS) -c $< -o $@
|
|||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
.INTERMEDIATE:
|
.INTERMEDIATE:
|
||||||
.PRECIOUS: $(OBJS) $(DEPS)
|
.PRECIOUS: $(OBJS) $(DEPS)
|
||||||
.PHONY: all clean help
|
.PHONY: all clean help cppcheck run
|
||||||
|
|
||||||
|
# Enable second expansion for more flexible rules
|
||||||
|
.SECONDEXPANSION:
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Targets
|
# Targets
|
||||||
@@ -154,7 +167,6 @@ $(OUTPUT): $(OBJS)
|
|||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(ECHO) Linking $@
|
@$(ECHO) Linking $@
|
||||||
$(LINK.o)
|
$(LINK.o)
|
||||||
$(SYMBOLS.out)
|
|
||||||
|
|
||||||
$(BUILD)/%.o: %.c
|
$(BUILD)/%.o: %.c
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@@ -182,8 +194,15 @@ clean:
|
|||||||
@$(RM) -rf $(BUILD) $(OUTPUT)
|
@$(RM) -rf $(BUILD) $(OUTPUT)
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo available targets: all run clean
|
@echo "Available targets:"
|
||||||
@echo $(OUTPUT)
|
@echo " all - Build the project (default)"
|
||||||
|
@echo " run - Build and run the executable"
|
||||||
|
@echo " clean - Remove build artifacts"
|
||||||
|
@echo " cppcheck - Run static analysis"
|
||||||
|
@echo " help - Show this help message"
|
||||||
|
@echo ""
|
||||||
|
@echo "Output: $(OUTPUT)"
|
||||||
|
@echo "Jobs: $(JOBS)"
|
||||||
|
|
||||||
-include $(DEPS)
|
-include $(DEPS)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { CssBaseline, ThemeProvider, responsiveFontSizes } from '@mui/material';
|
import {
|
||||||
|
CssBaseline,
|
||||||
|
ThemeProvider,
|
||||||
|
responsiveFontSizes,
|
||||||
|
tooltipClasses
|
||||||
|
} from '@mui/material';
|
||||||
import { createTheme } from '@mui/material/styles';
|
import { createTheme } from '@mui/material/styles';
|
||||||
|
|
||||||
import type { RequiredChildrenProps } from 'utils';
|
import type { RequiredChildrenProps } from 'utils';
|
||||||
@@ -44,6 +49,24 @@ const theme = responsiveFontSizes(
|
|||||||
color: '#9e9e9e' // grey[500]
|
color: '#9e9e9e' // grey[500]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
MuiTooltip: {
|
||||||
|
defaultProps: {
|
||||||
|
placement: 'top',
|
||||||
|
arrow: true
|
||||||
|
},
|
||||||
|
styleOverrides: {
|
||||||
|
tooltip: {
|
||||||
|
padding: '4px 8px',
|
||||||
|
fontSize: 10,
|
||||||
|
color: 'rgba(0, 0, 0, 0.87)',
|
||||||
|
backgroundColor: '#4caf50', // MUI success.main default color
|
||||||
|
boxShadow: '0px 2px 8px rgba(0, 0, 0, 0.15)',
|
||||||
|
[`& .${tooltipClasses.arrow}`]: {
|
||||||
|
color: '#4caf50'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ const CustomEntities = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Box mt={1} display="flex" flexWrap="wrap">
|
<Box mt={2} display="flex" flexWrap="wrap">
|
||||||
<Box flexGrow={1}>
|
<Box flexGrow={1}>
|
||||||
{numChanges > 0 && (
|
{numChanges > 0 && (
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
ToggleButton,
|
ToggleButton,
|
||||||
ToggleButtonGroup,
|
ToggleButtonGroup,
|
||||||
|
Tooltip,
|
||||||
Typography
|
Typography
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
@@ -284,37 +285,44 @@ const Dashboard = memo(() => {
|
|||||||
|
|
||||||
{data.nodes.length > 0 && (
|
{data.nodes.length > 0 && (
|
||||||
<>
|
<>
|
||||||
|
<Box
|
||||||
|
display="flex"
|
||||||
|
justifyContent="flex-end"
|
||||||
|
flexWrap="nowrap"
|
||||||
|
whiteSpace="nowrap"
|
||||||
|
>
|
||||||
<ToggleButtonGroup
|
<ToggleButtonGroup
|
||||||
color="primary"
|
|
||||||
size="small"
|
size="small"
|
||||||
|
color="primary"
|
||||||
value={showAll}
|
value={showAll}
|
||||||
exclusive
|
exclusive
|
||||||
onChange={handleShowAll}
|
onChange={handleShowAll}
|
||||||
>
|
>
|
||||||
<ButtonTooltip title={LL.ALLVALUES()} arrow>
|
<ButtonTooltip title={LL.ALLVALUES()}>
|
||||||
<ToggleButton value={true}>
|
<ToggleButton value={true}>
|
||||||
<UnfoldMoreIcon sx={{ fontSize: 18 }} />
|
<UnfoldMoreIcon sx={{ fontSize: 18 }} />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</ButtonTooltip>
|
</ButtonTooltip>
|
||||||
<ButtonTooltip title={LL.COMPACT()} arrow>
|
<ButtonTooltip title={LL.COMPACT()}>
|
||||||
<ToggleButton value={false}>
|
<ToggleButton value={false}>
|
||||||
<UnfoldLessIcon sx={{ fontSize: 18 }} />
|
<UnfoldLessIcon sx={{ fontSize: 18 }} />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</ButtonTooltip>
|
</ButtonTooltip>
|
||||||
</ToggleButtonGroup>
|
</ToggleButtonGroup>
|
||||||
<ButtonTooltip title={LL.DASHBOARD_1()} arrow>
|
<Tooltip title={LL.DASHBOARD_1()}>
|
||||||
<HelpOutlineIcon color="primary" sx={{ ml: 1, fontSize: 20 }} />
|
<HelpOutlineIcon
|
||||||
</ButtonTooltip>
|
|
||||||
|
|
||||||
<Box
|
|
||||||
padding={1}
|
|
||||||
justifyContent="center"
|
|
||||||
flexDirection="column"
|
|
||||||
sx={{
|
sx={{
|
||||||
borderRadius: 1,
|
ml: 1,
|
||||||
border: '1px solid rgb(65, 65, 65)'
|
mt: 1,
|
||||||
|
fontSize: 20,
|
||||||
|
verticalAlign: 'middle'
|
||||||
}}
|
}}
|
||||||
>
|
color="primary"
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
<Box mt={1} justifyContent="center" flexDirection="column">
|
||||||
<IconContext.Provider
|
<IconContext.Provider
|
||||||
value={{
|
value={{
|
||||||
color: 'lightblue',
|
color: 'lightblue',
|
||||||
|
|||||||
@@ -535,15 +535,7 @@ const Devices = memo(() => {
|
|||||||
|
|
||||||
const renderCoreData = () => (
|
const renderCoreData = () => (
|
||||||
<>
|
<>
|
||||||
<Box
|
<Box justifyContent="center" flexDirection="column">
|
||||||
padding={1}
|
|
||||||
justifyContent="center"
|
|
||||||
flexDirection="column"
|
|
||||||
sx={{
|
|
||||||
borderRadius: 1,
|
|
||||||
border: '1px solid rgb(65, 65, 65)'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IconContext.Provider
|
<IconContext.Provider
|
||||||
value={{
|
value={{
|
||||||
color: 'lightblue',
|
color: 'lightblue',
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ const Help = () => {
|
|||||||
divider={<Divider orientation="vertical" flexItem />}
|
divider={<Divider orientation="vertical" flexItem />}
|
||||||
sx={{
|
sx={{
|
||||||
borderRadius: 3,
|
borderRadius: 3,
|
||||||
border: '2px solid grey',
|
border: '1px solid lightblue',
|
||||||
justifyContent: 'space-evenly',
|
justifyContent: 'space-evenly',
|
||||||
alignItems: 'center'
|
alignItems: 'center'
|
||||||
}}
|
}}
|
||||||
@@ -99,7 +99,7 @@ const Help = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{me.admin && (
|
{me.admin && (
|
||||||
<List sx={{ borderRadius: 3, border: '2px solid grey' }}>
|
<List>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
component="a"
|
component="a"
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ const Scheduler = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Box mt={1} display="flex" flexWrap="wrap">
|
<Box display="flex" flexWrap="wrap">
|
||||||
<Box flexGrow={1}>
|
<Box flexGrow={1}>
|
||||||
{numChanges !== 0 && (
|
{numChanges !== 0 && (
|
||||||
<ButtonRow>
|
<ButtonRow>
|
||||||
|
|||||||
@@ -105,8 +105,6 @@ const Sensors = () => {
|
|||||||
color: #90CAF9;
|
color: #90CAF9;
|
||||||
.th {
|
.th {
|
||||||
border-bottom: 1px solid #565656;
|
border-bottom: 1px solid #565656;
|
||||||
}
|
|
||||||
.th {
|
|
||||||
height: 36px;
|
height: 36px;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -491,7 +489,7 @@ const Sensors = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{sensorData?.analog_enabled === true && me.admin && (
|
{sensorData?.analog_enabled === true && me.admin && (
|
||||||
<Box mt={1} display="flex" flexWrap="wrap" justifyContent="flex-end">
|
<Box mt={2} display="flex" flexWrap="wrap" justifyContent="flex-end">
|
||||||
<Button
|
<Button
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
|
Divider,
|
||||||
List
|
List
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
@@ -74,9 +75,9 @@ const Settings = () => {
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|
||||||
const content = () => (
|
return (
|
||||||
<>
|
<SectionContent>
|
||||||
<List sx={{ borderRadius: 3, border: '2px solid grey' }}>
|
<List>
|
||||||
<ListMenuItem
|
<ListMenuItem
|
||||||
icon={TuneIcon}
|
icon={TuneIcon}
|
||||||
bgcolor="#134ba2"
|
bgcolor="#134ba2"
|
||||||
@@ -143,7 +144,15 @@ const Settings = () => {
|
|||||||
|
|
||||||
{renderFactoryResetDialog()}
|
{renderFactoryResetDialog()}
|
||||||
|
|
||||||
<Box mt={2} display="flex" flexWrap="wrap">
|
<Divider />
|
||||||
|
|
||||||
|
<Box
|
||||||
|
mt={2}
|
||||||
|
display="flex"
|
||||||
|
justifyContent="flex-end"
|
||||||
|
flexWrap="nowrap"
|
||||||
|
whiteSpace="nowrap"
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<SettingsBackupRestoreIcon />}
|
startIcon={<SettingsBackupRestoreIcon />}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@@ -153,10 +162,8 @@ const Settings = () => {
|
|||||||
{LL.FACTORY_RESET()}
|
{LL.FACTORY_RESET()}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</SectionContent>
|
||||||
);
|
);
|
||||||
|
|
||||||
return <SectionContent>{content()}</SectionContent>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Settings;
|
export default Settings;
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ const SystemStatus = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<List sx={{ borderRadius: 3, border: '2px solid grey' }}>
|
<List>
|
||||||
<ListMenuItem
|
<ListMenuItem
|
||||||
icon={BuildIcon}
|
icon={BuildIcon}
|
||||||
bgcolor="#72caf9"
|
bgcolor="#72caf9"
|
||||||
|
|||||||
@@ -1,22 +1,7 @@
|
|||||||
import { Tooltip, type TooltipProps, styled, tooltipClasses } from '@mui/material';
|
import { Tooltip, type TooltipProps } from '@mui/material';
|
||||||
|
|
||||||
export const ButtonTooltip = styled(({ className, ...props }: TooltipProps) => (
|
export const ButtonTooltip = ({ children, ...props }: TooltipProps) => (
|
||||||
<Tooltip
|
<Tooltip {...props}>{children}</Tooltip>
|
||||||
{...props}
|
);
|
||||||
placement="top"
|
|
||||||
arrow
|
|
||||||
classes={{ ...(className && { popper: className }) }}
|
|
||||||
/>
|
|
||||||
))(({ theme }) => ({
|
|
||||||
[`& .${tooltipClasses.arrow}`]: {
|
|
||||||
color: theme.palette.success.main
|
|
||||||
},
|
|
||||||
[`& .${tooltipClasses.tooltip}`]: {
|
|
||||||
backgroundColor: theme.palette.success.main,
|
|
||||||
color: 'rgba(0, 0, 0, 0.87)',
|
|
||||||
boxShadow: theme.shadows[1],
|
|
||||||
fontSize: 10
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default ButtonTooltip;
|
export default ButtonTooltip;
|
||||||
|
|||||||
@@ -1,30 +1,20 @@
|
|||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { Divider, Paper } from '@mui/material';
|
import { Paper } from '@mui/material';
|
||||||
|
|
||||||
import type { RequiredChildrenProps } from 'utils';
|
import type { RequiredChildrenProps } from 'utils';
|
||||||
|
|
||||||
interface SectionContentProps extends RequiredChildrenProps {
|
interface SectionContentProps extends RequiredChildrenProps {
|
||||||
title?: string;
|
|
||||||
id?: string;
|
id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SectionContent: FC<SectionContentProps> = (props) => {
|
const SectionContent: FC<SectionContentProps> = (props) => {
|
||||||
const { children, title, id } = props;
|
const { children, id } = props;
|
||||||
return (
|
return (
|
||||||
<Paper id={id} sx={{ p: 2, m: 2 }}>
|
<Paper
|
||||||
{title && (
|
id={id}
|
||||||
<Divider
|
sx={{ p: 1.5, m: 1.5, borderRadius: 3, border: '1px solid rgb(65, 65, 65)' }}
|
||||||
sx={{
|
|
||||||
pb: 2,
|
|
||||||
borderColor: 'primary.main',
|
|
||||||
fontSize: 20,
|
|
||||||
color: 'primary.main'
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{title}
|
|
||||||
</Divider>
|
|
||||||
)}
|
|
||||||
{children}
|
{children}
|
||||||
</Paper>
|
</Paper>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user