eionet2-dashboard 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/.fx/configs/azure.parameters.Prod_EEA.json +15 -0
  2. package/.fx/configs/azure.parameters.dev.json +15 -0
  3. package/.fx/configs/config.Prod_EEA.json +10 -0
  4. package/.fx/configs/config.dev.json +10 -0
  5. package/.fx/configs/projectSettings.json +83 -0
  6. package/.fx/states/state.Prod_EEA.json +47 -0
  7. package/.fx/states/state.dev.json +47 -0
  8. package/.vscode/launch.json +91 -0
  9. package/.vscode/settings.json +6 -0
  10. package/.vscode/tasks.json +63 -0
  11. package/CHANGELOG.md +140 -0
  12. package/Jenkinsfile +166 -0
  13. package/LICENSE.md +9 -0
  14. package/README.md +55 -0
  15. package/api/.funcignore +11 -0
  16. package/api/extensions.csproj +11 -0
  17. package/api/getGraphData/function.json +27 -0
  18. package/api/getGraphData/index.js +147 -0
  19. package/api/host.json +11 -0
  20. package/api/package-lock.json +1546 -0
  21. package/api/package.json +17 -0
  22. package/api/proxies.json +4 -0
  23. package/package.json +25 -0
  24. package/tabs/.env.teamsfx.Prod_EEA +11 -0
  25. package/tabs/.env.teamsfx.dev +11 -0
  26. package/tabs/.eslintrc.json +48 -0
  27. package/tabs/.prettierrc +7 -0
  28. package/tabs/.stylelintrc.json +6 -0
  29. package/tabs/babel.config.js +3 -0
  30. package/tabs/package-lock.json +15564 -0
  31. package/tabs/package.json +88 -0
  32. package/tabs/public/auth-end.html +76 -0
  33. package/tabs/public/auth-start.html +178 -0
  34. package/tabs/public/deploy.png +0 -0
  35. package/tabs/public/favicon.ico +0 -0
  36. package/tabs/public/hello.png +0 -0
  37. package/tabs/public/index.html +20 -0
  38. package/tabs/public/publish.png +0 -0
  39. package/tabs/src/components/App.jsx +36 -0
  40. package/tabs/src/components/CustomColumnResizeIcon.jsx +68 -0
  41. package/tabs/src/components/CustomDrawer.jsx +51 -0
  42. package/tabs/src/components/EventDialogTitle.jsx +29 -0
  43. package/tabs/src/components/HtmlBox.jsx +18 -0
  44. package/tabs/src/components/Privacy.jsx +17 -0
  45. package/tabs/src/components/ResizableGrid.jsx +44 -0
  46. package/tabs/src/components/Tab.jsx +477 -0
  47. package/tabs/src/components/Tab.scss +138 -0
  48. package/tabs/src/components/TabConfig.jsx +51 -0
  49. package/tabs/src/components/TabPanel.jsx +29 -0
  50. package/tabs/src/components/TermsOfUse.jsx +17 -0
  51. package/tabs/src/components/UnderConstruction.jsx +24 -0
  52. package/tabs/src/components/UserMenu.jsx +109 -0
  53. package/tabs/src/components/_variables.scss +10 -0
  54. package/tabs/src/components/activity/Activity.jsx +301 -0
  55. package/tabs/src/components/activity/ConsultationList.jsx +297 -0
  56. package/tabs/src/components/activity/EventList.jsx +463 -0
  57. package/tabs/src/components/activity/GroupsTags.jsx +26 -0
  58. package/tabs/src/components/activity/Reporting.jsx +13 -0
  59. package/tabs/src/components/activity/activity.scss +153 -0
  60. package/tabs/src/components/event_rating/EventRating.jsx +92 -0
  61. package/tabs/src/components/event_rating/EventRatingDialog.jsx +46 -0
  62. package/tabs/src/components/event_registration/Approval.jsx +80 -0
  63. package/tabs/src/components/event_registration/ApprovalDialog.jsx +30 -0
  64. package/tabs/src/components/event_registration/ApprovalList.jsx +62 -0
  65. package/tabs/src/components/event_registration/EventRegistration.jsx +214 -0
  66. package/tabs/src/components/lib/useData.js +33 -0
  67. package/tabs/src/components/lib/useGraph.js +39 -0
  68. package/tabs/src/components/lib/useTeamsFx.js +55 -0
  69. package/tabs/src/components/my_country/AtAGlance.jsx +151 -0
  70. package/tabs/src/components/my_country/CountryProgress.jsx +92 -0
  71. package/tabs/src/components/my_country/DataReporters.jsx +13 -0
  72. package/tabs/src/components/my_country/GroupView.jsx +54 -0
  73. package/tabs/src/components/my_country/GroupsBoard.jsx +52 -0
  74. package/tabs/src/components/my_country/IndicatorCard.jsx +60 -0
  75. package/tabs/src/components/my_country/ManagementBoard.jsx +109 -0
  76. package/tabs/src/components/my_country/MyCountry.jsx +186 -0
  77. package/tabs/src/components/my_country/ProgressGauge.jsx +125 -0
  78. package/tabs/src/components/my_country/ScientificCommittee.jsx +13 -0
  79. package/tabs/src/components/my_country/YearlyProgress.jsx +41 -0
  80. package/tabs/src/components/my_country/my_country.scss +81 -0
  81. package/tabs/src/components/publications/Publications.jsx +13 -0
  82. package/tabs/src/components/self_service/UserEdit.jsx +334 -0
  83. package/tabs/src/components/self_service/UserEdit.scss +107 -0
  84. package/tabs/src/data/apiProvider.js +153 -0
  85. package/tabs/src/data/constants.json +7 -0
  86. package/tabs/src/data/hooks/useConfiguration.js +18 -0
  87. package/tabs/src/data/icsHelper.js +38 -0
  88. package/tabs/src/data/messages.json +39 -0
  89. package/tabs/src/data/provider.js +199 -0
  90. package/tabs/src/data/selfServiceProvider.js +59 -0
  91. package/tabs/src/data/selfServiceSharepointProvider.js +68 -0
  92. package/tabs/src/data/sharepointProvider.js +729 -0
  93. package/tabs/src/data/validator.js +25 -0
  94. package/tabs/src/data/validator.test.js +9 -0
  95. package/tabs/src/index.css +16 -0
  96. package/tabs/src/index.jsx +6 -0
  97. package/tabs/src/static/images/teams-icon.svg +1 -0
  98. package/tabs/src/utils/uiHelper.js +6 -0
  99. package/templates/appPackage/aad.template.json +133 -0
  100. package/templates/appPackage/manifest.template.json +58 -0
  101. package/templates/appPackage/resources/color.png +0 -0
  102. package/templates/appPackage/resources/outline.png +0 -0
  103. package/templates/azure/config.bicep +27 -0
  104. package/templates/azure/main.bicep +20 -0
  105. package/templates/azure/provision/frontendHosting.bicep +23 -0
  106. package/templates/azure/provision/function.bicep +82 -0
  107. package/templates/azure/provision/identity.bicep +14 -0
  108. package/templates/azure/provision/simpleAuth.bicep +44 -0
  109. package/templates/azure/provision.bicep +58 -0
  110. package/templates/azure/teamsFx/function.bicep +76 -0
  111. package/templates/azure/teamsFx/simpleAuth.bicep +43 -0
@@ -0,0 +1,151 @@
1
+ import { React, useState, useEffect } from 'react';
2
+ import { Box, Typography, Backdrop, CircularProgress } from '@mui/material';
3
+ import { IndicatorCard } from './IndicatorCard';
4
+ import { CountryProgress } from './CountryProgress';
5
+ import { getGroups } from '../../data/sharepointProvider';
6
+ import { HtmlBox } from '../HtmlBox';
7
+ import { getMeetings, getConsultations } from '../../data/sharepointProvider';
8
+
9
+ export function AtAGlance({
10
+ users,
11
+ organisations,
12
+ country,
13
+ userInfo,
14
+ configuration,
15
+ availableGroups,
16
+ }) {
17
+ const signedInUsers = users.filter((u) => {
18
+ return u.SignedIn;
19
+ }),
20
+ signedInGroups = getGroups(signedInUsers),
21
+ pendingSignInUsers = users.filter((u) => {
22
+ return !u.SignedIn;
23
+ }),
24
+ pendingSignInGroups = getGroups(pendingSignInUsers),
25
+ nominationsGroups = [...new Set(signedInGroups.concat(pendingSignInGroups))],
26
+ countryFilterSuffix = country ? '?FilterField1=Country&FilterValue1=' + country + '&' : '?';
27
+
28
+ const [lastYears, setLastYears] = useState([]),
29
+ [loading, setLoading] = useState(false);
30
+
31
+ useEffect(() => {
32
+ const fetchData = async () => {
33
+ setLoading(true);
34
+
35
+ //get meetings from last two years
36
+ const fromDate = new Date(new Date().getFullYear() - 2, 0, 1);
37
+ let loadedMeetings = await getMeetings(fromDate, country, userInfo),
38
+ loadedConsultations = await getConsultations(undefined, fromDate);
39
+
40
+ const current = new Date().getFullYear();
41
+ let years = [];
42
+ for (let i = current; i >= current - 1; i--) {
43
+ const allMeetings = loadedMeetings.filter((m) => m.Year == i),
44
+ allConsultations = loadedConsultations.filter(
45
+ (c) => c.Year == i && c.ConsultationType == 'Consultation',
46
+ ),
47
+ allSurveys = loadedConsultations.filter(
48
+ (c) => c.Year == i && c.ConsultationType == 'Inquiry',
49
+ );
50
+
51
+ const result = {
52
+ year: i,
53
+ meetingsCount: allMeetings.length,
54
+ consultationsCount: allConsultations.length,
55
+ surveysCount: allSurveys.length,
56
+ attendedMeetingsCount: allMeetings.filter((meeting) => {
57
+ return meeting.Participants.some((participant) => participant.Country == country);
58
+ }).length,
59
+ responseConsultationsCount: allConsultations.filter((c) => {
60
+ return c.Respondants.includes(country);
61
+ }).length,
62
+ responseSurveysCount: allSurveys.filter((c) => {
63
+ return c.Respondants.includes(country);
64
+ }).length,
65
+ };
66
+ years.push(result);
67
+ }
68
+ setLastYears(years);
69
+ setLoading(false);
70
+ };
71
+ fetchData();
72
+ }, [country, userInfo]);
73
+
74
+ return (
75
+ <div className="">
76
+ <Box
77
+ sx={{
78
+ height: '100%',
79
+ overflowX: 'hidden',
80
+ }}
81
+ >
82
+ <Backdrop
83
+ sx={{ color: '#6b32a8', zIndex: (theme) => theme.zIndex.drawer + 1 }}
84
+ open={loading}
85
+ >
86
+ <CircularProgress color="primary" />
87
+ </Backdrop>
88
+ <Typography
89
+ sx={{ fontSize: '16px', fontWeight: '600', pt: '12px', pl: '12px' }}
90
+ color="text.secondary"
91
+ >
92
+ Representation:
93
+ </Typography>
94
+ <Box className="cards-container" sx={{ border: '0px' }}>
95
+ <IndicatorCard
96
+ labelText="members"
97
+ valueText={users.length}
98
+ url={configuration.UserListUrl + countryFilterSuffix}
99
+ infoText={configuration.NoOfMembersCardInfo}
100
+ ></IndicatorCard>
101
+ <IndicatorCard
102
+ labelText="members pending sign in"
103
+ valueText={users.length - signedInUsers.length}
104
+ url={
105
+ configuration.UserListUrl +
106
+ countryFilterSuffix +
107
+ 'FilterField2=SignedIn&FilterValue2=0'
108
+ }
109
+ infoText={configuration.MembersPendingSingInCardInfo}
110
+ ></IndicatorCard>
111
+ <IndicatorCard
112
+ labelText="organisations"
113
+ valueText={organisations.length}
114
+ url={configuration.OrganisationListUrl + countryFilterSuffix}
115
+ infoText={configuration.NoOfOrganisationsCardInfo}
116
+ ></IndicatorCard>
117
+ <IndicatorCard
118
+ labelText="groups with nominations"
119
+ valueText={nominationsGroups.length + '/' + availableGroups.length}
120
+ infoText={configuration.GroupsWithNominationsCardInfo}
121
+ ></IndicatorCard>
122
+ <IndicatorCard
123
+ labelText="groups with signed in users"
124
+ valueText={signedInGroups.length + '/' + availableGroups.length}
125
+ infoText={configuration.GroupsWithSignedInUsersCardInfo}
126
+ ></IndicatorCard>
127
+ </Box>
128
+ {country && (
129
+ <Box sx={{ marginLeft: '1rem' }}>
130
+ <HtmlBox html={configuration.CountryProgressHtml}></HtmlBox>
131
+ </Box>
132
+ )}
133
+ {country && (
134
+ <Box
135
+ sx={{
136
+ display: 'flex',
137
+ flexDirection: 'column',
138
+ width: '100%',
139
+ flexGrow: 1,
140
+ marginLeft: '1rem',
141
+ borderTop: 1,
142
+ borderColor: 'divider',
143
+ }}
144
+ >
145
+ <CountryProgress lastYears={lastYears} configuration={configuration}></CountryProgress>
146
+ </Box>
147
+ )}
148
+ </Box>
149
+ </div>
150
+ );
151
+ }
@@ -0,0 +1,92 @@
1
+ import { React, useState } from 'react';
2
+ import { Box, Typography, Tab, Tabs } from '@mui/material';
3
+ import PropTypes from 'prop-types';
4
+ import { YearlyProgress } from './YearlyProgress';
5
+ function TabPanel(props) {
6
+ const { children, value, index, ...other } = props;
7
+
8
+ return (
9
+ <div
10
+ role="tabpanel"
11
+ hidden={value !== index}
12
+ id={`simple-tabpanel-${index}`}
13
+ aria-labelledby={`simple-tab-${index}`}
14
+ {...other}
15
+ >
16
+ {value === index && (
17
+ <Box sx={{ pt: 1, borderTop: 1, borderColor: 'secondary.main' }}>
18
+ <Typography component={'span'}>{children}</Typography>
19
+ </Box>
20
+ )}
21
+ </div>
22
+ );
23
+ }
24
+
25
+ TabPanel.propTypes = {
26
+ children: PropTypes.node,
27
+ index: PropTypes.number.isRequired,
28
+ value: PropTypes.number.isRequired,
29
+ };
30
+
31
+ function a11yProps(index) {
32
+ return {
33
+ id: `simple-tab-${index}`,
34
+ 'aria-controls': `simple-tabpanel-${index}`,
35
+ };
36
+ }
37
+
38
+ export function CountryProgress({ lastYears, configuration }) {
39
+ const [tabsValue, setTabsValue] = useState(0),
40
+ handleChange = (_event, newValue) => {
41
+ setTabsValue(newValue);
42
+ };
43
+
44
+ return (
45
+ <div className="">
46
+ {lastYears.length > 0 && (
47
+ <Box sx={{ display: 'flex', flexDirection: 'column' }}>
48
+ <Typography
49
+ sx={{ fontSize: '16px', fontWeight: '600', paddingTop: '12px' }}
50
+ color="text.secondary"
51
+ >
52
+ Yearly overview:
53
+ </Typography>
54
+ <Tabs
55
+ TabIndicatorProps={{
56
+ sx: {
57
+ bottom: 0,
58
+ height: 10,
59
+ backgroundColor: 'secondary.main',
60
+ clipPath: 'polygon(50% 0, 0 100%, 100% 100%)',
61
+ },
62
+ }}
63
+ value={tabsValue}
64
+ onChange={handleChange}
65
+ >
66
+ {lastYears.map((year, index) => {
67
+ return (
68
+ <Tab className="year-tab" key={index} label={year.year} {...a11yProps(index)} />
69
+ );
70
+ })}
71
+ </Tabs>
72
+ {lastYears.map((year, index) => {
73
+ return (
74
+ <TabPanel className="year-panel" key={index} value={tabsValue} index={index}>
75
+ <YearlyProgress
76
+ allMeetingsCount={year.meetingsCount}
77
+ allConsultationsCount={year.consultationsCount}
78
+ allSurveysCount={year.surveysCount}
79
+ attendedMeetingsCount={year.attendedMeetingsCount}
80
+ responseConsultationsCount={year.responseConsultationsCount}
81
+ responseSurveysCount={year.responseSurveysCount}
82
+ year={year.year}
83
+ configuration={configuration}
84
+ ></YearlyProgress>
85
+ </TabPanel>
86
+ );
87
+ })}
88
+ </Box>
89
+ )}
90
+ </div>
91
+ );
92
+ }
@@ -0,0 +1,13 @@
1
+ import { React } from 'react';
2
+ import { Box } from '@mui/material';
3
+ import { UnderConstruction } from '../UnderConstruction';
4
+
5
+ export function DataReporters() {
6
+ return (
7
+ <div className="">
8
+ <Box className="box-fill">
9
+ <UnderConstruction></UnderConstruction>
10
+ </Box>
11
+ </div>
12
+ );
13
+ }
@@ -0,0 +1,54 @@
1
+ import { React } from 'react';
2
+ import './my_country.scss';
3
+ import ResizableGrid from '../ResizableGrid';
4
+ import { Box } from '@mui/material';
5
+
6
+ export function GroupView({ group }) {
7
+ const columns = [
8
+ {
9
+ field: 'Organisation',
10
+ headerName: 'Organisation',
11
+ flex: 1.5,
12
+ },
13
+ {
14
+ field: 'Title',
15
+ headerName: 'Name',
16
+ flex: 0.75,
17
+ },
18
+ {
19
+ field: 'Email',
20
+ headerName: 'Email',
21
+ flex: 0.75,
22
+ },
23
+ ];
24
+ return (
25
+ <Box
26
+ sx={{
27
+ display: 'flex',
28
+ height: '98%',
29
+ width: '100%',
30
+ }}
31
+ >
32
+ {group && (
33
+ <ResizableGrid
34
+ id={group.GroupName}
35
+ rows={group.Users}
36
+ columns={columns}
37
+ hideFooterSelectedRowCount
38
+ pageSizeOptions={[25, 50, 100]}
39
+ initialState={{
40
+ pagination: { paginationModel: { pageSize: 25 } },
41
+ sorting: {
42
+ sortModel: [
43
+ {
44
+ field: 'Organisation',
45
+ sort: 'asc',
46
+ },
47
+ ],
48
+ },
49
+ }}
50
+ />
51
+ )}
52
+ </Box>
53
+ );
54
+ }
@@ -0,0 +1,52 @@
1
+ import { React, useState } from 'react';
2
+ import { Box, ListItem, ListItemButton, ListItemText } from '@mui/material';
3
+ import { GroupView } from './GroupView';
4
+ import CustomDrawer from '../CustomDrawer';
5
+
6
+ export function GroupsBoard({ users, mappings }) {
7
+ const [groupIndex, setGroupIndex] = useState(0),
8
+ groups = mappings
9
+ .map((m) => {
10
+ const filteredUsers = users.filter((user) => {
11
+ return user.AllMemberships.includes(m.Membership);
12
+ });
13
+ return {
14
+ GroupName: m.Membership,
15
+ Users: filteredUsers,
16
+ };
17
+ })
18
+ .filter((group) => group.Users.length > 0),
19
+ drawerOptions = (
20
+ <div>
21
+ {groups.map((currentGroup, index) => {
22
+ return (
23
+ <ListItem disablePadding className="list-item" key={index}>
24
+ <ListItemButton
25
+ className={
26
+ 'list-item-button ' + (groupIndex == index ? ' drawer-item-selected' : '')
27
+ }
28
+ onClick={() => setGroupIndex(index)}
29
+ >
30
+ <ListItemText primary={currentGroup.GroupName} />
31
+ </ListItemButton>
32
+ </ListItem>
33
+ );
34
+ })}
35
+ </div>
36
+ );
37
+
38
+ return (
39
+ <Box
40
+ sx={{
41
+ overflowY: 'scroll',
42
+ display: 'flex',
43
+ width: '100%',
44
+ height: '98%',
45
+ background: 'white',
46
+ }}
47
+ >
48
+ <CustomDrawer drawerOptions={drawerOptions}></CustomDrawer>
49
+ <GroupView group={groups[groupIndex]}></GroupView>
50
+ </Box>
51
+ );
52
+ }
@@ -0,0 +1,60 @@
1
+ import { React, useState } from 'react';
2
+ import { Typography, Card, CardContent, Dialog, Link, Button, IconButton } from '@mui/material';
3
+ import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
4
+
5
+ export function IndicatorCard({ labelText, valueText, url, infoText }) {
6
+ const [infoOpen, setInfoOpen] = useState(false),
7
+ handleInfoOpen = () => {
8
+ infoText && setInfoOpen(true);
9
+ },
10
+ handleInfoClose = () => {
11
+ setInfoOpen(false);
12
+ };
13
+
14
+ return (
15
+ <Card variant="outlined" className="indicator-card">
16
+ <Dialog open={infoOpen} onClose={handleInfoClose} maxWidth="xl">
17
+ <Typography sx={{ padding: '1rem' }} color="secondary">
18
+ {infoText}
19
+ </Typography>
20
+ <Button
21
+ onClick={handleInfoClose}
22
+ sx={{ alignSelf: 'end', marginRight: '0.5rem', marginBottom: '0.5rem' }}
23
+ >
24
+ Close
25
+ </Button>
26
+ </Dialog>
27
+ <CardContent className="card-content">
28
+ <Typography className="card-value" color="primary" variant="h1" component="div">
29
+ {valueText}
30
+ </Typography>
31
+ <Typography className="card-label">{labelText}</Typography>
32
+ <IconButton
33
+ onClick={handleInfoOpen}
34
+ sx={{
35
+ position: 'absolute',
36
+ right: 0,
37
+ top: 0,
38
+ color: (theme) => theme.palette.grey[500],
39
+ }}
40
+ >
41
+ <HelpOutlineIcon />
42
+ </IconButton>
43
+ </CardContent>
44
+ {url && (
45
+ <Link
46
+ sx={{ color: 'text.main' }}
47
+ className="card-details"
48
+ color="secondary"
49
+ component="button"
50
+ variant="body1"
51
+ onClick={() => {
52
+ window.open(url, '_blank');
53
+ }}
54
+ >
55
+ {'Details'}
56
+ </Link>
57
+ )}
58
+ </Card>
59
+ );
60
+ }
@@ -0,0 +1,109 @@
1
+ import { React } from 'react';
2
+ import { Box, Chip, Tooltip } from '@mui/material';
3
+ import ResizableGrid from '../ResizableGrid';
4
+
5
+ export function ManagementBoard({ users, mappings }) {
6
+ const boardMappings = mappings.filter((mp) => {
7
+ return mp.ManagementBoard;
8
+ }),
9
+ currentUsers = users
10
+ .filter((u) => {
11
+ return (
12
+ u.NFP ||
13
+ (u.Membership &&
14
+ u.Membership.some((m) => boardMappings.some((mapping) => mapping.Membership == m)))
15
+ );
16
+ })
17
+ .map((user) => {
18
+ const boardMembership =
19
+ user.NFP ||
20
+ (user.Membership &&
21
+ user.Membership.find((m) => boardMappings.some((mapping) => mapping.Membership == m)));
22
+ return {
23
+ id: user.id,
24
+ Organisation: user.Organisation,
25
+ Name: user.Title,
26
+ Email: user.Email,
27
+ BoardMembership: boardMembership,
28
+ OtherMemberships: user.OtherMemberships,
29
+ Membership: user.Membership,
30
+ };
31
+ }),
32
+ renderOtherMemberships = (params) => {
33
+ let index = 0,
34
+ allMemberships = [];
35
+
36
+ params.row.Membership && params.row.Membership.forEach((m) => allMemberships.push(m));
37
+ params.row.OtherMemberships &&
38
+ params.row.OtherMemberships.forEach((m) => allMemberships.push(m));
39
+ params.row.NFP && allMemberships.push(params.row.NFP);
40
+
41
+ allMemberships = allMemberships.filter((m) => m != params.row.BoardMembership);
42
+
43
+ return (
44
+ <Tooltip title={allMemberships.join(', ') || ''} arrow>
45
+ <div id="test">
46
+ {allMemberships.map((m) => (
47
+ <Chip variant="outlined" color="primary" key={index++} label={m} />
48
+ ))}
49
+ </div>
50
+ </Tooltip>
51
+ );
52
+ };
53
+
54
+ const columns = [
55
+ {
56
+ field: 'Organisation',
57
+ headerName: 'Organisation',
58
+ flex: 1.5,
59
+ },
60
+ {
61
+ field: 'BoardMembership',
62
+ headerName: 'Membership',
63
+ flex: 0.75,
64
+ },
65
+ {
66
+ field: 'Name',
67
+ headerName: 'Name',
68
+ flex: 0.75,
69
+ },
70
+ {
71
+ field: 'Email',
72
+ headerName: 'Email',
73
+ flex: 0.75,
74
+ },
75
+ {
76
+ field: 'OtherMemberships',
77
+ headerName: 'Other Memberships',
78
+ flex: 0.75,
79
+ renderCell: renderOtherMemberships,
80
+ },
81
+ ];
82
+ return (
83
+ <Box
84
+ sx={{
85
+ background: 'white',
86
+ height: '97%',
87
+ width: '100%',
88
+ }}
89
+ >
90
+ <ResizableGrid
91
+ rows={currentUsers}
92
+ columns={columns}
93
+ pageSize={25}
94
+ rowsPerPageOptions={[25]}
95
+ hideFooterSelectedRowCount={true}
96
+ initialState={{
97
+ sorting: {
98
+ sortModel: [
99
+ {
100
+ field: 'BoardMembership',
101
+ sort: 'asc',
102
+ },
103
+ ],
104
+ },
105
+ }}
106
+ ></ResizableGrid>
107
+ </Box>
108
+ );
109
+ }