ApiLogicServer 15.0.37__py3-none-any.whl → 15.0.40__py3-none-any.whl
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.
- api_logic_server_cli/api_logic_server.py +2 -2
- api_logic_server_cli/api_logic_server_info.yaml +2 -2
- api_logic_server_cli/genai/genai_svcs.py +4 -3
- api_logic_server_cli/prototypes/base/.copilot-instructions.md +10 -0
- api_logic_server_cli/prototypes/base/.vscode/.copilot-instructions.md +178 -0
- api_logic_server_cli/prototypes/base/README_PROJECT.md +43 -0
- api_logic_server_cli/prototypes/base/api_logic_server_run.py +20 -8
- api_logic_server_cli/prototypes/base/docs/training/react_map.prompt.md +13 -0
- api_logic_server_cli/prototypes/base/docs/training/react_tree.prompt.md +10 -0
- api_logic_server_cli/prototypes/base/integration/mcp/readme-mcp.md +9 -0
- api_logic_server_cli/prototypes/base/logic/logic_discovery/readme_logic_discovery.md +9 -0
- api_logic_server_cli/prototypes/base/logic/logic_discovery/use_case.py +27 -0
- api_logic_server_cli/prototypes/base/logic/{readme_declare_logic.md → readme_logic.md} +70 -1
- api_logic_server_cli/prototypes/base/readme.md +30 -5
- api_logic_server_cli/prototypes/base/security/readme_security.md +17 -0
- api_logic_server_cli/prototypes/manager/.copilot-instructions.md +13 -0
- api_logic_server_cli/prototypes/manager/.vscode/.copilot-instructions.md +58 -0
- api_logic_server_cli/prototypes/manager/.vscode/ApiLogicServer.code-workspace +2 -2
- api_logic_server_cli/prototypes/manager/README.md +13 -1
- api_logic_server_cli/prototypes/manager/system/Manager_workspace.code-workspace +3 -3
- api_logic_server_cli/prototypes/nw/api/api_discovery/authentication_expose_api_models.py +53 -0
- api_logic_server_cli/prototypes/nw/api/api_discovery/auto_discovery.py +27 -0
- api_logic_server_cli/prototypes/nw/api/api_discovery/count_orders_by_month.html +76 -0
- api_logic_server_cli/prototypes/nw/api/api_discovery/count_orders_by_month.sql +1 -0
- api_logic_server_cli/prototypes/nw/api/api_discovery/dashboard_services.py +143 -0
- api_logic_server_cli/prototypes/nw/api/api_discovery/mcp_discovery.py +97 -0
- api_logic_server_cli/prototypes/nw/api/api_discovery/new_service.py +21 -0
- api_logic_server_cli/prototypes/nw/api/api_discovery/newer_service.py +21 -0
- api_logic_server_cli/prototypes/nw/api/api_discovery/number_of_sales_per_category.html +76 -0
- api_logic_server_cli/prototypes/nw/api/api_discovery/number_of_sales_per_category.sql +1 -0
- api_logic_server_cli/prototypes/nw/api/api_discovery/ontimize_api.py +495 -0
- api_logic_server_cli/prototypes/nw/api/api_discovery/sales_by_category.html +76 -0
- api_logic_server_cli/prototypes/nw/api/api_discovery/sales_by_category.sql +1 -0
- api_logic_server_cli/prototypes/nw/api/api_discovery/system.py +77 -0
- api_logic_server_cli/prototypes/nw/database/database_discovery/graphics_services.py +173 -0
- api_logic_server_cli/prototypes/nw/ui/admin/home.js +5 -0
- api_logic_server_cli/prototypes/nw/ui/reference_react_app/DEPARTMENT_TREE_VIEW.md +66 -0
- api_logic_server_cli/prototypes/nw/ui/reference_react_app/README.md +21 -4
- api_logic_server_cli/prototypes/nw/ui/reference_react_app/package.json +4 -0
- api_logic_server_cli/prototypes/nw/ui/reference_react_app/public/index.html +3 -0
- api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/App.js +8 -1
- api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/CustomLayout.js +20 -0
- api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/Department.js +511 -24
- api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/DepartmentTree.js +147 -0
- api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/Employee.js +230 -18
- api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/LandingPage.js +264 -0
- api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/Supplier.js +359 -121
- api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/index.js +1 -0
- {apilogicserver-15.0.37.dist-info → apilogicserver-15.0.40.dist-info}/METADATA +1 -1
- {apilogicserver-15.0.37.dist-info → apilogicserver-15.0.40.dist-info}/RECORD +54 -25
- api_logic_server_cli/prototypes/base/docs/training/admin_app_unused.md +0 -156
- {apilogicserver-15.0.37.dist-info → apilogicserver-15.0.40.dist-info}/WHEEL +0 -0
- {apilogicserver-15.0.37.dist-info → apilogicserver-15.0.40.dist-info}/entry_points.txt +0 -0
- {apilogicserver-15.0.37.dist-info → apilogicserver-15.0.40.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-15.0.37.dist-info → apilogicserver-15.0.40.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
const DepartmentTree = () => {
|
|
4
|
+
const [departments, setDepartments] = useState([]);
|
|
5
|
+
const [expandedNodes, setExpandedNodes] = useState(new Set());
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
// Fetch departments from API Logic Server
|
|
9
|
+
fetchDepartments();
|
|
10
|
+
}, []);
|
|
11
|
+
|
|
12
|
+
const fetchDepartments = async () => {
|
|
13
|
+
try {
|
|
14
|
+
const response = await fetch('/api/Department');
|
|
15
|
+
const data = await response.json();
|
|
16
|
+
setDepartments(buildTree(data.data));
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.error('Error fetching departments:', error);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const buildTree = (flatData) => {
|
|
23
|
+
const map = {};
|
|
24
|
+
const tree = [];
|
|
25
|
+
|
|
26
|
+
// Create a map of all departments
|
|
27
|
+
flatData.forEach(dept => {
|
|
28
|
+
map[dept.Id] = { ...dept, children: [] };
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Build the tree structure
|
|
32
|
+
flatData.forEach(dept => {
|
|
33
|
+
if (dept.DepartmentId && map[dept.DepartmentId]) {
|
|
34
|
+
// This department has a parent
|
|
35
|
+
map[dept.DepartmentId].children.push(map[dept.Id]);
|
|
36
|
+
} else {
|
|
37
|
+
// This is a root department
|
|
38
|
+
tree.push(map[dept.Id]);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return tree;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const toggleNode = (nodeId) => {
|
|
46
|
+
const newExpanded = new Set(expandedNodes);
|
|
47
|
+
if (newExpanded.has(nodeId)) {
|
|
48
|
+
newExpanded.delete(nodeId);
|
|
49
|
+
} else {
|
|
50
|
+
newExpanded.add(nodeId);
|
|
51
|
+
}
|
|
52
|
+
setExpandedNodes(newExpanded);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const TreeNode = ({ node, level = 0 }) => {
|
|
56
|
+
const hasChildren = node.children && node.children.length > 0;
|
|
57
|
+
const isExpanded = expandedNodes.has(node.Id);
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div className="tree-node">
|
|
61
|
+
<div
|
|
62
|
+
className="tree-node-content"
|
|
63
|
+
style={{ paddingLeft: `${level * 20}px` }}
|
|
64
|
+
>
|
|
65
|
+
{hasChildren && (
|
|
66
|
+
<span
|
|
67
|
+
className={`tree-toggle ${isExpanded ? 'expanded' : 'collapsed'}`}
|
|
68
|
+
onClick={() => toggleNode(node.Id)}
|
|
69
|
+
>
|
|
70
|
+
{isExpanded ? '▼' : '▶'}
|
|
71
|
+
</span>
|
|
72
|
+
)}
|
|
73
|
+
<span className="tree-node-label">
|
|
74
|
+
{node.DepartmentName} (Level: {node.SecurityLevel})
|
|
75
|
+
</span>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
{hasChildren && isExpanded && (
|
|
79
|
+
<div className="tree-children">
|
|
80
|
+
{node.children.map(child => (
|
|
81
|
+
<TreeNode
|
|
82
|
+
key={child.Id}
|
|
83
|
+
node={child}
|
|
84
|
+
level={level + 1}
|
|
85
|
+
/>
|
|
86
|
+
))}
|
|
87
|
+
</div>
|
|
88
|
+
)}
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<div className="department-tree">
|
|
95
|
+
<h2>Department Hierarchy</h2>
|
|
96
|
+
<div className="tree-container">
|
|
97
|
+
{departments.map(dept => (
|
|
98
|
+
<TreeNode key={dept.Id} node={dept} />
|
|
99
|
+
))}
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<style jsx>{`
|
|
103
|
+
.department-tree {
|
|
104
|
+
padding: 20px;
|
|
105
|
+
font-family: Arial, sans-serif;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.tree-container {
|
|
109
|
+
border: 1px solid #ddd;
|
|
110
|
+
border-radius: 4px;
|
|
111
|
+
padding: 10px;
|
|
112
|
+
background-color: #f9f9f9;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.tree-node-content {
|
|
116
|
+
display: flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
padding: 4px 0;
|
|
119
|
+
cursor: pointer;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.tree-node-content:hover {
|
|
123
|
+
background-color: #e6f3ff;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.tree-toggle {
|
|
127
|
+
margin-right: 8px;
|
|
128
|
+
font-size: 12px;
|
|
129
|
+
color: #666;
|
|
130
|
+
cursor: pointer;
|
|
131
|
+
user-select: none;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.tree-node-label {
|
|
135
|
+
font-weight: 500;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.tree-children {
|
|
139
|
+
border-left: 1px dashed #ccc;
|
|
140
|
+
margin-left: 10px;
|
|
141
|
+
}
|
|
142
|
+
`}</style>
|
|
143
|
+
</div>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export default DepartmentTree;
|
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
// begin MANDATORY imports (always generated
|
|
2
|
-
import React from 'react';
|
|
1
|
+
// begin MANDATORY imports (always generated)
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
3
|
import { List, FunctionField, Datagrid, TextField, EmailField, DateField, NumberField } from 'react-admin';
|
|
4
4
|
import { ReferenceField, ReferenceManyField } from 'react-admin';
|
|
5
5
|
import { TabbedShowLayout, Tab, SimpleShowLayout, TextInput, NumberInput, DateTimeInput } from 'react-admin';
|
|
6
6
|
import { ReferenceInput, SelectInput, SimpleForm, Show, Edit, Create } from 'react-admin';
|
|
7
7
|
import { Filter, Pagination, BooleanField, BooleanInput, Labeled } from 'react-admin';
|
|
8
8
|
import { EditButton, DeleteButton, CreateButton, ShowButton } from 'react-admin';
|
|
9
|
-
import { Grid, Typography, Box, Divider, Button } from '@mui/material';
|
|
10
|
-
import { useRecordContext, useRedirect, Link, required } from 'react-admin';
|
|
9
|
+
import { Grid, Typography, Box, Divider, Button, Card, CardContent, CardActions, ToggleButton, ToggleButtonGroup, Avatar } from '@mui/material';
|
|
10
|
+
import { useRecordContext, useRedirect, Link, required, useListContext } from 'react-admin';
|
|
11
11
|
import AddIcon from '@mui/icons-material/Add';
|
|
12
|
+
import ViewListIcon from '@mui/icons-material/ViewList';
|
|
13
|
+
import ViewModuleIcon from '@mui/icons-material/ViewModule';
|
|
14
|
+
import PersonIcon from '@mui/icons-material/Person';
|
|
15
|
+
import WorkIcon from '@mui/icons-material/Work';
|
|
16
|
+
import AttachMoneyIcon from '@mui/icons-material/AttachMoney';
|
|
17
|
+
import EmailIcon from '@mui/icons-material/Email';
|
|
12
18
|
// end mandatory imports
|
|
13
19
|
|
|
14
20
|
const EmployeeFilter = (props) => (
|
|
@@ -17,23 +23,202 @@ const EmployeeFilter = (props) => (
|
|
|
17
23
|
</Filter>
|
|
18
24
|
);
|
|
19
25
|
|
|
26
|
+
// Employee Card View Component
|
|
27
|
+
const EmployeeCard = ({ record }) => (
|
|
28
|
+
<Card sx={{
|
|
29
|
+
minWidth: 300,
|
|
30
|
+
maxWidth: 350,
|
|
31
|
+
height: 320,
|
|
32
|
+
margin: 1,
|
|
33
|
+
display: 'flex',
|
|
34
|
+
flexDirection: 'column',
|
|
35
|
+
transition: 'transform 0.2s, box-shadow 0.2s',
|
|
36
|
+
'&:hover': {
|
|
37
|
+
transform: 'translateY(-2px)',
|
|
38
|
+
boxShadow: 3
|
|
39
|
+
}
|
|
40
|
+
}}>
|
|
41
|
+
<CardContent sx={{ flexGrow: 1, pb: 1 }}>
|
|
42
|
+
{/* Employee Photo */}
|
|
43
|
+
<Box sx={{ display: 'flex', justifyContent: 'center', mb: 2 }}>
|
|
44
|
+
{record.PhotoPath ? (
|
|
45
|
+
<Avatar
|
|
46
|
+
src={record.PhotoPath}
|
|
47
|
+
alt={`${record.FirstName} ${record.LastName}`}
|
|
48
|
+
sx={{ width: 80, height: 80 }}
|
|
49
|
+
/>
|
|
50
|
+
) : (
|
|
51
|
+
<Avatar sx={{ width: 80, height: 80, bgcolor: 'primary.main' }}>
|
|
52
|
+
<PersonIcon sx={{ fontSize: 40 }} />
|
|
53
|
+
</Avatar>
|
|
54
|
+
)}
|
|
55
|
+
</Box>
|
|
56
|
+
|
|
57
|
+
<Typography variant="h6" component="div" sx={{
|
|
58
|
+
mb: 2,
|
|
59
|
+
fontWeight: 'bold',
|
|
60
|
+
color: 'primary.main',
|
|
61
|
+
textAlign: 'center',
|
|
62
|
+
overflow: 'hidden',
|
|
63
|
+
textOverflow: 'ellipsis',
|
|
64
|
+
whiteSpace: 'nowrap'
|
|
65
|
+
}}>
|
|
66
|
+
{record.FirstName} {record.LastName}
|
|
67
|
+
</Typography>
|
|
68
|
+
|
|
69
|
+
<Box sx={{ mb: 1.5, display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
70
|
+
<WorkIcon color="action" fontSize="small" />
|
|
71
|
+
<Typography variant="body2" color="text.secondary">
|
|
72
|
+
{record.Title || 'No title'}
|
|
73
|
+
</Typography>
|
|
74
|
+
</Box>
|
|
75
|
+
|
|
76
|
+
<Box sx={{ mb: 1.5, display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
77
|
+
<AttachMoneyIcon color="action" fontSize="small" />
|
|
78
|
+
<Typography variant="body1" sx={{ fontWeight: 'medium' }}>
|
|
79
|
+
{record.Salary ? `$${record.Salary.toLocaleString()}` : 'No salary info'}
|
|
80
|
+
</Typography>
|
|
81
|
+
</Box>
|
|
82
|
+
|
|
83
|
+
{record.Email && (
|
|
84
|
+
<Box sx={{ mb: 1.5, display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
85
|
+
<EmailIcon color="action" fontSize="small" />
|
|
86
|
+
<Typography variant="body2" color="text.secondary" sx={{
|
|
87
|
+
overflow: 'hidden',
|
|
88
|
+
textOverflow: 'ellipsis',
|
|
89
|
+
whiteSpace: 'nowrap'
|
|
90
|
+
}}>
|
|
91
|
+
{record.Email}
|
|
92
|
+
</Typography>
|
|
93
|
+
</Box>
|
|
94
|
+
)}
|
|
95
|
+
</CardContent>
|
|
96
|
+
|
|
97
|
+
<CardActions sx={{ pt: 0, pb: 2, px: 2, justifyContent: 'space-between' }}>
|
|
98
|
+
<ShowButton record={record} size="small" />
|
|
99
|
+
<Box>
|
|
100
|
+
<EditButton record={record} size="small" sx={{ mr: 1 }} />
|
|
101
|
+
<DeleteButton record={record} size="small" />
|
|
102
|
+
</Box>
|
|
103
|
+
</CardActions>
|
|
104
|
+
</Card>
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// Employee Grid View Component
|
|
108
|
+
const EmployeeGridView = () => {
|
|
109
|
+
const { data, isLoading } = useListContext();
|
|
110
|
+
|
|
111
|
+
if (isLoading) return <div>Loading...</div>;
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<Grid container spacing={2} sx={{ mt: 1 }}>
|
|
115
|
+
{data?.map(record => (
|
|
116
|
+
<Grid item key={record.id} xs={12} sm={6} md={4} lg={3}>
|
|
117
|
+
<EmployeeCard record={record} />
|
|
118
|
+
</Grid>
|
|
119
|
+
))}
|
|
120
|
+
</Grid>
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// View Toggle Component
|
|
125
|
+
const ViewToggle = ({ viewMode, setViewMode }) => (
|
|
126
|
+
<Box sx={{ mb: 2, display: 'flex', justifyContent: 'flex-end' }}>
|
|
127
|
+
<ToggleButtonGroup
|
|
128
|
+
value={viewMode}
|
|
129
|
+
exclusive
|
|
130
|
+
onChange={(event, newViewMode) => {
|
|
131
|
+
if (newViewMode !== null) {
|
|
132
|
+
setViewMode(newViewMode);
|
|
133
|
+
}
|
|
134
|
+
}}
|
|
135
|
+
aria-label="view mode"
|
|
136
|
+
size="small"
|
|
137
|
+
>
|
|
138
|
+
<ToggleButton value="list" aria-label="list view">
|
|
139
|
+
<ViewListIcon />
|
|
140
|
+
</ToggleButton>
|
|
141
|
+
<ToggleButton value="cards" aria-label="card view">
|
|
142
|
+
<ViewModuleIcon />
|
|
143
|
+
</ToggleButton>
|
|
144
|
+
</ToggleButtonGroup>
|
|
145
|
+
</Box>
|
|
146
|
+
);
|
|
147
|
+
|
|
20
148
|
// Employee List
|
|
21
149
|
export const EmployeeList = (props) => {
|
|
150
|
+
const [viewMode, setViewMode] = useState('list');
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<>
|
|
154
|
+
<ViewToggle viewMode={viewMode} setViewMode={setViewMode} />
|
|
155
|
+
<List filters={<EmployeeFilter />} {...props} sort={{ field: 'LastName', order: 'ASC' }} pagination={<Pagination rowsPerPageOptions={[5, 10, 25]} showFirstLastButtons />}>
|
|
156
|
+
{viewMode === 'list' ? (
|
|
157
|
+
<Datagrid rowClick="show">
|
|
158
|
+
<TextField source="LastName" label="Last Name" />
|
|
159
|
+
<TextField source="FirstName" label="First Name" />
|
|
160
|
+
<EmailField source="Email" label="Email" />
|
|
161
|
+
<NumberField source="Salary" label="Salary" options={{ style: 'currency', currency: 'USD'}} />
|
|
162
|
+
<ReferenceField source="WorksForDepartmentId" reference="Department" label="Department">
|
|
163
|
+
<TextField source="DepartmentName" />
|
|
164
|
+
</ReferenceField>
|
|
165
|
+
<EditButton />
|
|
166
|
+
<DeleteButton />
|
|
167
|
+
<ShowButton />
|
|
168
|
+
</Datagrid>
|
|
169
|
+
) : (
|
|
170
|
+
<EmployeeGridView />
|
|
171
|
+
)}
|
|
172
|
+
</List>
|
|
173
|
+
</>
|
|
174
|
+
);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// Custom Photo Display Component
|
|
178
|
+
const EmployeePhotoDisplay = () => {
|
|
179
|
+
const record = useRecordContext();
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
<Box sx={{ display: 'flex', justifyContent: 'center', mb: 3 }}>
|
|
183
|
+
{record?.PhotoPath ? (
|
|
184
|
+
<Avatar
|
|
185
|
+
src={record.PhotoPath}
|
|
186
|
+
alt={`${record.FirstName} ${record.LastName}`}
|
|
187
|
+
sx={{ width: 120, height: 120 }}
|
|
188
|
+
/>
|
|
189
|
+
) : (
|
|
190
|
+
<Avatar sx={{ width: 120, height: 120, bgcolor: 'primary.main' }}>
|
|
191
|
+
<PersonIcon sx={{ fontSize: 60 }} />
|
|
192
|
+
</Avatar>
|
|
193
|
+
)}
|
|
194
|
+
</Box>
|
|
195
|
+
);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// Custom Photo Field Component
|
|
199
|
+
const PhotoField = () => {
|
|
200
|
+
const record = useRecordContext();
|
|
201
|
+
|
|
22
202
|
return (
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
203
|
+
<Box sx={{ mt: 1 }}>
|
|
204
|
+
{record?.PhotoPath ? (
|
|
205
|
+
<img
|
|
206
|
+
src={record.PhotoPath}
|
|
207
|
+
alt={`${record.FirstName} ${record.LastName}`}
|
|
208
|
+
style={{
|
|
209
|
+
width: '60px',
|
|
210
|
+
height: '60px',
|
|
211
|
+
borderRadius: '50%',
|
|
212
|
+
objectFit: 'cover',
|
|
213
|
+
border: '2px solid #ddd'
|
|
214
|
+
}}
|
|
215
|
+
/>
|
|
216
|
+
) : (
|
|
217
|
+
<Avatar sx={{ width: 60, height: 60, bgcolor: 'grey.300' }}>
|
|
218
|
+
<PersonIcon />
|
|
219
|
+
</Avatar>
|
|
220
|
+
)}
|
|
221
|
+
</Box>
|
|
37
222
|
);
|
|
38
223
|
};
|
|
39
224
|
|
|
@@ -46,6 +231,10 @@ export const EmployeeShow = (props) => {
|
|
|
46
231
|
<Typography variant="h5" component="h2" sx={{ mb: 2, fontWeight: 'bold' }}>
|
|
47
232
|
Employee Information
|
|
48
233
|
</Typography>
|
|
234
|
+
|
|
235
|
+
{/* Employee Photo Section */}
|
|
236
|
+
<EmployeePhotoDisplay />
|
|
237
|
+
|
|
49
238
|
<Grid container spacing={3} sx={{ mb: 2 }}>
|
|
50
239
|
<Grid item xs={12} sm={6} md={3}>
|
|
51
240
|
<Box sx={{ p: 1 }}>
|
|
@@ -61,6 +250,13 @@ export const EmployeeShow = (props) => {
|
|
|
61
250
|
</Labeled>
|
|
62
251
|
</Box>
|
|
63
252
|
</Grid>
|
|
253
|
+
<Grid item xs={12} sm={6} md={3}>
|
|
254
|
+
<Box sx={{ p: 1 }}>
|
|
255
|
+
<Labeled label="Title">
|
|
256
|
+
<TextField source="Title" />
|
|
257
|
+
</Labeled>
|
|
258
|
+
</Box>
|
|
259
|
+
</Grid>
|
|
64
260
|
<Grid item xs={12} sm={6} md={3}>
|
|
65
261
|
<Box sx={{ p: 1 }}>
|
|
66
262
|
<Labeled label="Salary">
|
|
@@ -75,6 +271,22 @@ export const EmployeeShow = (props) => {
|
|
|
75
271
|
</Labeled>
|
|
76
272
|
</Box>
|
|
77
273
|
</Grid>
|
|
274
|
+
<Grid item xs={12} sm={6} md={3}>
|
|
275
|
+
<Box sx={{ p: 1 }}>
|
|
276
|
+
<Labeled label="Department">
|
|
277
|
+
<ReferenceField source="WorksForDepartmentId" reference="Department">
|
|
278
|
+
<TextField source="DepartmentName" />
|
|
279
|
+
</ReferenceField>
|
|
280
|
+
</Labeled>
|
|
281
|
+
</Box>
|
|
282
|
+
</Grid>
|
|
283
|
+
<Grid item xs={12} sm={6} md={3}>
|
|
284
|
+
<Box sx={{ p: 1 }}>
|
|
285
|
+
<Labeled label="Hire Date">
|
|
286
|
+
<DateField source="HireDate" />
|
|
287
|
+
</Labeled>
|
|
288
|
+
</Box>
|
|
289
|
+
</Grid>
|
|
78
290
|
</Grid>
|
|
79
291
|
<Divider sx={{ my: 2 }} />
|
|
80
292
|
</Box>
|