ApiLogicServer 15.0.35__py3-none-any.whl → 15.0.38__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.
Files changed (45) hide show
  1. api_logic_server_cli/api_logic_server.py +2 -2
  2. api_logic_server_cli/api_logic_server_info.yaml +3 -3
  3. api_logic_server_cli/genai/genai_svcs.py +4 -3
  4. api_logic_server_cli/manager.py +7 -5
  5. api_logic_server_cli/prototypes/base/docs/training/react_map.prompt.md +13 -0
  6. api_logic_server_cli/prototypes/base/docs/training/react_tree.prompt.md +10 -0
  7. api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_context_results.txt +142 -0
  8. api_logic_server_cli/prototypes/base/integration/mcp/mcp_client_executor.py +65 -29
  9. api_logic_server_cli/prototypes/manager/system/Manager_workspace.code-workspace +3 -3
  10. api_logic_server_cli/prototypes/manager/system/genai/app_templates/app_learning/Admin-App-Resource-Learning-Prompt.md +3 -2
  11. api_logic_server_cli/prototypes/manager/system/genai/app_templates/app_learning/Admin-App-js-Learning-Prompt.md +4 -14
  12. api_logic_server_cli/prototypes/nw/api/api_discovery/authentication_expose_api_models.py +53 -0
  13. api_logic_server_cli/prototypes/nw/api/api_discovery/auto_discovery.py +27 -0
  14. api_logic_server_cli/prototypes/nw/api/api_discovery/count_orders_by_month.html +76 -0
  15. api_logic_server_cli/prototypes/nw/api/api_discovery/count_orders_by_month.sql +1 -0
  16. api_logic_server_cli/prototypes/nw/api/api_discovery/dashboard_services.py +143 -0
  17. api_logic_server_cli/prototypes/nw/api/api_discovery/mcp_discovery.py +97 -0
  18. api_logic_server_cli/prototypes/nw/api/api_discovery/new_service.py +21 -0
  19. api_logic_server_cli/prototypes/nw/api/api_discovery/newer_service.py +21 -0
  20. api_logic_server_cli/prototypes/nw/api/api_discovery/number_of_sales_per_category.html +76 -0
  21. api_logic_server_cli/prototypes/nw/api/api_discovery/number_of_sales_per_category.sql +1 -0
  22. api_logic_server_cli/prototypes/nw/api/api_discovery/ontimize_api.py +495 -0
  23. api_logic_server_cli/prototypes/nw/api/api_discovery/sales_by_category.html +76 -0
  24. api_logic_server_cli/prototypes/nw/api/api_discovery/sales_by_category.sql +1 -0
  25. api_logic_server_cli/prototypes/nw/api/api_discovery/system.py +77 -0
  26. api_logic_server_cli/prototypes/nw/database/database_discovery/graphics_services.py +173 -0
  27. api_logic_server_cli/prototypes/nw/ui/admin/home.js +5 -0
  28. api_logic_server_cli/prototypes/nw/ui/reference_react_app/DEPARTMENT_TREE_VIEW.md +66 -0
  29. api_logic_server_cli/prototypes/nw/ui/reference_react_app/package.json +4 -0
  30. api_logic_server_cli/prototypes/nw/ui/reference_react_app/public/index.html +3 -0
  31. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/App.js +8 -1
  32. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/CustomLayout.js +20 -0
  33. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/Department.js +511 -24
  34. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/DepartmentTree.js +147 -0
  35. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/Employee.js +230 -18
  36. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/LandingPage.js +264 -0
  37. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/Supplier.js +359 -121
  38. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/index.js +1 -0
  39. {apilogicserver-15.0.35.dist-info → apilogicserver-15.0.38.dist-info}/METADATA +1 -1
  40. {apilogicserver-15.0.35.dist-info → apilogicserver-15.0.38.dist-info}/RECORD +44 -23
  41. api_logic_server_cli/prototypes/base/docs/training/admin_app_unused.md +0 -156
  42. {apilogicserver-15.0.35.dist-info → apilogicserver-15.0.38.dist-info}/WHEEL +0 -0
  43. {apilogicserver-15.0.35.dist-info → apilogicserver-15.0.38.dist-info}/entry_points.txt +0 -0
  44. {apilogicserver-15.0.35.dist-info → apilogicserver-15.0.38.dist-info}/licenses/LICENSE +0 -0
  45. {apilogicserver-15.0.35.dist-info → apilogicserver-15.0.38.dist-info}/top_level.txt +0 -0
@@ -1,24 +1,450 @@
1
- // begin MANDATORY imports (always generated EXACTLY)
2
- import React from 'react';
3
- import { List, FunctionField, Datagrid, TextField, EmailField, DateField, NumberField } from 'react-admin';
1
+ // begin MANDATORY imports (always generated)
2
+ import React, { useState } from 'react';
3
+ import { List, Datagrid, TextField, DateField, NumberField } from 'react-admin';
4
4
  import { ReferenceField, ReferenceManyField } from 'react-admin';
5
- import { TabbedShowLayout, Tab, SimpleShowLayout, TextInput, NumberInput, DateTimeInput } from 'react-admin';
5
+ import { SimpleShowLayout, TextInput, NumberInput } from 'react-admin';
6
6
  import { ReferenceInput, SelectInput, SimpleForm, Show, Edit, Create } from 'react-admin';
7
- import { Filter, Pagination, BooleanField, BooleanInput, Labeled } from 'react-admin';
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';
7
+ import { Pagination, Labeled } from 'react-admin';
8
+ import { EditButton, DeleteButton, CreateButton } from 'react-admin';
9
+ import { Grid, Typography, Box, Divider, Button, ToggleButton, ToggleButtonGroup, Paper, Collapse, IconButton, Tabs, Tab as MuiTab } from '@mui/material';
10
+ import { useRecordContext, useRedirect, useGetList } from 'react-admin';
11
11
  import AddIcon from '@mui/icons-material/Add';
12
+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
13
+ import ChevronRightIcon from '@mui/icons-material/ChevronRight';
14
+ import ViewListIcon from '@mui/icons-material/ViewList';
15
+ import AccountTreeIcon from '@mui/icons-material/AccountTree';
12
16
  // end mandatory imports
13
17
 
14
- export const DepartmentList = (props) => (
15
- <List {...props} sort={{ field: 'DepartmentName', order: 'ASC' }} pagination={<Pagination rowsPerPageOptions={[5, 10, 25]} showFirstLastButtons />}>
16
- <Datagrid rowClick="show">
17
- <TextField source="DepartmentName" label="Department Name" />
18
- <NumberField source="SecurityLevel" label="Security Level" />
19
- </Datagrid>
20
- </List>
21
- );
18
+ // Expandable Tree Node Component
19
+ const ExpandableTreeNode = ({ department, allDepartments, onDepartmentClick, level = 0 }) => {
20
+ const [expanded, setExpanded] = useState(false);
21
+
22
+ // Get children for this department - children have this department as their parent
23
+ const children = allDepartments?.filter(dept =>
24
+ dept.DepartmentId && parseInt(dept.DepartmentId) === parseInt(department.id)
25
+ ) || [];
26
+
27
+ const hasChildren = children.length > 0;
28
+
29
+ const handleToggle = () => {
30
+ if (hasChildren) {
31
+ setExpanded(!expanded);
32
+ }
33
+ };
34
+
35
+ return (
36
+ <Box>
37
+ {/* Department Row */}
38
+ <Box sx={{ display: 'flex', alignItems: 'center', mb: 0.5 }}>
39
+ {/* Expand/Collapse Icon */}
40
+ <IconButton
41
+ size="small"
42
+ onClick={handleToggle}
43
+ sx={{
44
+ width: 24,
45
+ height: 24,
46
+ mr: 0.5,
47
+ visibility: hasChildren ? 'visible' : 'hidden'
48
+ }}
49
+ >
50
+ {expanded ? <ExpandMoreIcon fontSize="small" /> : <ChevronRightIcon fontSize="small" />}
51
+ </IconButton>
52
+
53
+ {/* Department Button */}
54
+ <Button
55
+ variant="text"
56
+ onClick={() => onDepartmentClick(department)}
57
+ sx={{
58
+ textAlign: 'left',
59
+ textTransform: 'none',
60
+ fontWeight: level === 0 ? 'bold' : 'normal',
61
+ justifyContent: 'flex-start',
62
+ p: 0.5,
63
+ color: level === 0 ? 'text.primary' : level === 1 ? 'text.secondary' : 'text.disabled',
64
+ fontSize: level === 0 ? '1rem' : level === 1 ? '0.9rem' : '0.85rem',
65
+ minWidth: 'auto',
66
+ flex: 1
67
+ }}
68
+ >
69
+ {level === 0 ? '📁' : level === 1 ? '📄' : '📃'} {department.DepartmentName}
70
+ </Button>
71
+ </Box>
72
+
73
+ {/* Children (with collapse animation) */}
74
+ {hasChildren && (
75
+ <Collapse in={expanded}>
76
+ <Box sx={{ ml: 3 }}>
77
+ {children.map(child => (
78
+ <ExpandableTreeNode
79
+ key={child.id}
80
+ department={child}
81
+ allDepartments={allDepartments}
82
+ onDepartmentClick={onDepartmentClick}
83
+ level={level + 1}
84
+ />
85
+ ))}
86
+ </Box>
87
+ </Collapse>
88
+ )}
89
+ </Box>
90
+ );
91
+ };
92
+
93
+ // Department Tree View Component
94
+ const DepartmentTreeView = ({ onDepartmentClick }) => {
95
+ const { data: allDepartments, isLoading, error } = useGetList('Department', {
96
+ pagination: { page: 1, perPage: 1000 },
97
+ sort: { field: 'DepartmentName', order: 'ASC' }
98
+ });
99
+
100
+ if (isLoading) return <div>Loading departments...</div>;
101
+ if (error) return <div>Error loading departments: {error.message}</div>;
102
+
103
+ // Get root departments (those with no parent)
104
+ const rootDepartments = allDepartments?.filter(d => !d.DepartmentId || d.DepartmentId === null) || [];
105
+
106
+ return (
107
+ <Paper sx={{ p: 2, height: '100%', overflow: 'auto' }}>
108
+ <Typography variant="h6" sx={{ mb: 2 }}>
109
+ Department Hierarchy
110
+ </Typography>
111
+ {rootDepartments.length === 0 ? (
112
+ <Typography variant="body2" color="text.secondary">
113
+ No departments found
114
+ </Typography>
115
+ ) : (
116
+ <Box>
117
+ {rootDepartments.map(rootDept => (
118
+ <ExpandableTreeNode
119
+ key={rootDept.id}
120
+ department={rootDept}
121
+ allDepartments={allDepartments}
122
+ onDepartmentClick={onDepartmentClick}
123
+ level={0}
124
+ />
125
+ ))}
126
+ </Box>
127
+ )}
128
+ </Paper>
129
+ );
130
+ };
131
+
132
+ // Enhanced Department List with View Toggle
133
+ export const DepartmentList = (props) => {
134
+ const [viewMode, setViewMode] = useState('list');
135
+ const [selectedDepartment, setSelectedDepartment] = useState(null);
136
+
137
+ const handleViewChange = (event, newView) => {
138
+ if (newView !== null) {
139
+ setViewMode(newView);
140
+ }
141
+ };
142
+
143
+ const handleDepartmentClick = (department) => {
144
+ setSelectedDepartment(department);
145
+ };
146
+
147
+ if (viewMode === 'tree') {
148
+ return (
149
+ <Box sx={{ p: 2 }}>
150
+ <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
151
+ <Typography variant="h4">Departments</Typography>
152
+ <Box sx={{ display: 'flex', gap: 2, alignItems: 'center' }}>
153
+ <CreateButton />
154
+ <ToggleButtonGroup
155
+ value={viewMode}
156
+ exclusive
157
+ onChange={handleViewChange}
158
+ size="small"
159
+ >
160
+ <ToggleButton value="list">
161
+ <ViewListIcon sx={{ mr: 1 }} />
162
+ List
163
+ </ToggleButton>
164
+ <ToggleButton value="tree">
165
+ <AccountTreeIcon sx={{ mr: 1 }} />
166
+ Tree
167
+ </ToggleButton>
168
+ </ToggleButtonGroup>
169
+ </Box>
170
+ </Box>
171
+
172
+ <Grid container spacing={2} sx={{ height: 'calc(100vh - 200px)' }}>
173
+ <Grid item xs={12} md={selectedDepartment ? 6 : 12}>
174
+ <DepartmentTreeView onDepartmentClick={handleDepartmentClick} />
175
+ </Grid>
176
+ {selectedDepartment && (
177
+ <Grid item xs={12} md={6}>
178
+ <Paper sx={{ p: 2, height: '100%', overflow: 'auto' }}>
179
+ <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
180
+ <Typography variant="h6">
181
+ {selectedDepartment.DepartmentName}
182
+ </Typography>
183
+ <Button
184
+ variant="outlined"
185
+ onClick={() => setSelectedDepartment(null)}
186
+ size="small"
187
+ >
188
+ Close
189
+ </Button>
190
+ </Box>
191
+ <DepartmentDetails department={selectedDepartment} />
192
+ </Paper>
193
+ </Grid>
194
+ )}
195
+ </Grid>
196
+ </Box>
197
+ );
198
+ }
199
+
200
+ return (
201
+ <Box sx={{ p: 2 }}>
202
+ <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
203
+ <Typography variant="h4">Departments</Typography>
204
+ <ToggleButtonGroup
205
+ value={viewMode}
206
+ exclusive
207
+ onChange={handleViewChange}
208
+ size="small"
209
+ >
210
+ <ToggleButton value="list">
211
+ <ViewListIcon sx={{ mr: 1 }} />
212
+ List
213
+ </ToggleButton>
214
+ <ToggleButton value="tree">
215
+ <AccountTreeIcon sx={{ mr: 1 }} />
216
+ Tree
217
+ </ToggleButton>
218
+ </ToggleButtonGroup>
219
+ </Box>
220
+ <List {...props} sort={{ field: 'DepartmentName', order: 'ASC' }} pagination={<Pagination rowsPerPageOptions={[5, 10, 25]} showFirstLastButtons />}>
221
+ <Datagrid rowClick="show">
222
+ <TextField source="DepartmentName" label="Department Name" />
223
+ <NumberField source="SecurityLevel" label="Security Level" />
224
+ <ReferenceField source="DepartmentId" reference="Department" label="Parent Department">
225
+ <TextField source="DepartmentName" />
226
+ </ReferenceField>
227
+ </Datagrid>
228
+ </List>
229
+ </Box>
230
+ );
231
+ };
232
+
233
+ // Department Details Component (for the split view)
234
+ const DepartmentDetails = ({ department }) => {
235
+ const [tabValue, setTabValue] = useState(0);
236
+
237
+ const { data: allDepartments } = useGetList('Department', {
238
+ pagination: { page: 1, perPage: 1000 },
239
+ sort: { field: 'DepartmentName', order: 'ASC' }
240
+ });
241
+
242
+ const { data: employees } = useGetList('Employee', {
243
+ filter: { WorksForDepartmentId: department.id },
244
+ pagination: { page: 1, perPage: 100 },
245
+ sort: { field: 'LastName', order: 'ASC' }
246
+ });
247
+
248
+ // Filter sub-departments on the client side (fix the ID comparison)
249
+ const subDepartments = allDepartments?.filter(dept =>
250
+ dept.DepartmentId && parseInt(dept.DepartmentId) === parseInt(department.id)
251
+ ) || [];
252
+
253
+ // Find parent department if exists (fix the ID comparison)
254
+ const parentDepartment = department.DepartmentId ?
255
+ allDepartments?.find(dept => parseInt(dept.id) === parseInt(department.DepartmentId)) : null;
256
+
257
+ const handleTabChange = (event, newValue) => {
258
+ setTabValue(newValue);
259
+ };
260
+
261
+ return (
262
+ <Box sx={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
263
+ {/* Department Information Header */}
264
+ <Box sx={{ mb: 3 }}>
265
+ <Typography variant="h5" component="h2" sx={{ mb: 2, fontWeight: 'bold' }}>
266
+ Department Information
267
+ </Typography>
268
+ <Grid container spacing={3} sx={{ mb: 2 }}>
269
+ <Grid item xs={12} sm={6} md={4}>
270
+ <Box sx={{ p: 1 }}>
271
+ <Typography variant="body2" color="text.secondary" sx={{ mb: 0.5 }}>
272
+ Department Name
273
+ </Typography>
274
+ <Typography variant="body1" sx={{ fontWeight: 'medium' }}>
275
+ {department.DepartmentName}
276
+ </Typography>
277
+ </Box>
278
+ </Grid>
279
+ <Grid item xs={12} sm={6} md={4}>
280
+ <Box sx={{ p: 1 }}>
281
+ <Typography variant="body2" color="text.secondary" sx={{ mb: 0.5 }}>
282
+ Security Level
283
+ </Typography>
284
+ <Typography variant="body1" sx={{ fontWeight: 'medium' }}>
285
+ {department.SecurityLevel}
286
+ </Typography>
287
+ </Box>
288
+ </Grid>
289
+ <Grid item xs={12} sm={6} md={4}>
290
+ <Box sx={{ p: 1 }}>
291
+ <Typography variant="body2" color="text.secondary" sx={{ mb: 0.5 }}>
292
+ Parent Department
293
+ </Typography>
294
+ <Typography variant="body1" sx={{ fontWeight: 'medium' }}>
295
+ {parentDepartment ? parentDepartment.DepartmentName : 'No Parent'}
296
+ </Typography>
297
+ </Box>
298
+ </Grid>
299
+ </Grid>
300
+ <Divider sx={{ my: 2 }} />
301
+ </Box>
302
+
303
+ {/* Tabbed Content */}
304
+ <Box sx={{ flexGrow: 1 }}>
305
+ <Tabs value={tabValue} onChange={handleTabChange} sx={{ borderBottom: 1, borderColor: 'divider' }}>
306
+ <MuiTab label={`Sub-Departments (${subDepartments.length})`} />
307
+ <MuiTab label={`Employees (${employees?.length || 0})`} />
308
+ </Tabs>
309
+
310
+ {/* Tab Panels */}
311
+ {tabValue === 0 && (
312
+ <Box sx={{ p: 2, height: 'calc(100% - 48px)', overflow: 'auto' }}>
313
+ {subDepartments.length === 0 ? (
314
+ <Typography variant="body2" color="text.secondary">
315
+ No sub-departments found
316
+ </Typography>
317
+ ) : (
318
+ <Box>
319
+ {subDepartments.map(subDept => (
320
+ <Paper key={subDept.id} sx={{ p: 2, mb: 1 }}>
321
+ <Grid container spacing={2}>
322
+ <Grid item xs={6}>
323
+ <Typography variant="body2" color="text.secondary">Department Name</Typography>
324
+ <Typography variant="body1">{subDept.DepartmentName}</Typography>
325
+ </Grid>
326
+ <Grid item xs={6}>
327
+ <Typography variant="body2" color="text.secondary">Security Level</Typography>
328
+ <Typography variant="body1">{subDept.SecurityLevel}</Typography>
329
+ </Grid>
330
+ </Grid>
331
+ </Paper>
332
+ ))}
333
+ </Box>
334
+ )}
335
+ </Box>
336
+ )}
337
+
338
+ {tabValue === 1 && (
339
+ <Box sx={{ p: 2, height: 'calc(100% - 48px)', overflow: 'auto' }}>
340
+ {!employees || employees.length === 0 ? (
341
+ <Typography variant="body2" color="text.secondary">
342
+ No employees found
343
+ </Typography>
344
+ ) : (
345
+ <EmployeeGrid employees={employees} />
346
+ )}
347
+ </Box>
348
+ )}
349
+ </Box>
350
+ </Box>
351
+ );
352
+ };
353
+
354
+ // Employee Grid Component (for displaying employees in table format)
355
+ const EmployeeGrid = ({ employees }) => {
356
+ const redirect = useRedirect();
357
+
358
+ const handleEmployeeClick = (employee) => {
359
+ redirect(`/Employee/${employee.id}/show`);
360
+ };
361
+
362
+ return (
363
+ <Paper sx={{ width: '100%', overflow: 'hidden' }}>
364
+ <Box sx={{
365
+ display: 'grid',
366
+ gridTemplateColumns: '2fr 2fr 1.5fr 1fr',
367
+ gap: 0,
368
+ '& > div': {
369
+ p: 1,
370
+ borderBottom: '1px solid',
371
+ borderColor: 'divider',
372
+ borderRight: '1px solid',
373
+ borderRightColor: 'divider',
374
+ }
375
+ }}>
376
+ {/* Header Row */}
377
+ <Box sx={{ fontWeight: 'bold', bgcolor: 'grey.100' }}>
378
+ <Typography variant="body2" color="text.secondary">Name</Typography>
379
+ </Box>
380
+ <Box sx={{ fontWeight: 'bold', bgcolor: 'grey.100' }}>
381
+ <Typography variant="body2" color="text.secondary">Title</Typography>
382
+ </Box>
383
+ <Box sx={{ fontWeight: 'bold', bgcolor: 'grey.100' }}>
384
+ <Typography variant="body2" color="text.secondary">Hire Date</Typography>
385
+ </Box>
386
+ <Box sx={{ fontWeight: 'bold', bgcolor: 'grey.100', borderRight: 'none' }}>
387
+ <Typography variant="body2" color="text.secondary">Salary</Typography>
388
+ </Box>
389
+
390
+ {/* Data Rows */}
391
+ {employees.map(employee => (
392
+ <React.Fragment key={employee.id}>
393
+ <Box
394
+ sx={{
395
+ cursor: 'pointer',
396
+ '&:hover': { bgcolor: 'action.hover' },
397
+ transition: 'background-color 0.2s'
398
+ }}
399
+ onClick={() => handleEmployeeClick(employee)}
400
+ >
401
+ <Typography variant="body2" sx={{ fontWeight: 'medium' }}>
402
+ {employee.FirstName} {employee.LastName}
403
+ </Typography>
404
+ </Box>
405
+ <Box
406
+ sx={{
407
+ cursor: 'pointer',
408
+ '&:hover': { bgcolor: 'action.hover' },
409
+ transition: 'background-color 0.2s'
410
+ }}
411
+ onClick={() => handleEmployeeClick(employee)}
412
+ >
413
+ <Typography variant="body2">
414
+ {employee.Title || 'N/A'}
415
+ </Typography>
416
+ </Box>
417
+ <Box
418
+ sx={{
419
+ cursor: 'pointer',
420
+ '&:hover': { bgcolor: 'action.hover' },
421
+ transition: 'background-color 0.2s'
422
+ }}
423
+ onClick={() => handleEmployeeClick(employee)}
424
+ >
425
+ <Typography variant="body2">
426
+ {employee.HireDate ? new Date(employee.HireDate).toLocaleDateString() : 'N/A'}
427
+ </Typography>
428
+ </Box>
429
+ <Box
430
+ sx={{
431
+ cursor: 'pointer',
432
+ '&:hover': { bgcolor: 'action.hover' },
433
+ transition: 'background-color 0.2s',
434
+ borderRight: 'none'
435
+ }}
436
+ onClick={() => handleEmployeeClick(employee)}
437
+ >
438
+ <Typography variant="body2">
439
+ {employee.Salary ? `$${employee.Salary.toLocaleString()}` : 'N/A'}
440
+ </Typography>
441
+ </Box>
442
+ </React.Fragment>
443
+ ))}
444
+ </Box>
445
+ </Paper>
446
+ );
447
+ };
22
448
 
23
449
  // Department Show
24
450
  export const DepartmentShow = (props) => (
@@ -43,12 +469,36 @@ export const DepartmentShow = (props) => (
43
469
  </Labeled>
44
470
  </Box>
45
471
  </Grid>
472
+ <Grid item xs={12} sm={6} md={3}>
473
+ <Box sx={{ p: 1 }}>
474
+ <Labeled label="Parent Department">
475
+ <ReferenceField source="DepartmentId" reference="Department" emptyText="No Parent">
476
+ <TextField source="DepartmentName" />
477
+ </ReferenceField>
478
+ </Labeled>
479
+ </Box>
480
+ </Grid>
46
481
  </Grid>
47
482
  <Divider sx={{ my: 2 }} />
48
483
  </Box>
49
- </SimpleShowLayout>
50
- <TabbedShowLayout>
51
- <Tab label="Employee List">
484
+
485
+ {/* Sub-Departments */}
486
+ <Box sx={{ mb: 3 }}>
487
+ <Typography variant="h6" sx={{ mb: 2 }}>Sub-Departments</Typography>
488
+ <ReferenceManyField reference="Department" target="DepartmentId" addLabel={false} pagination={<Pagination />}>
489
+ <Datagrid rowClick="show">
490
+ <TextField source="DepartmentName" label="Department Name" />
491
+ <NumberField source="SecurityLevel" label="Security Level" />
492
+ <EditButton />
493
+ <DeleteButton />
494
+ </Datagrid>
495
+ </ReferenceManyField>
496
+ <AddSubDepartmentButton />
497
+ </Box>
498
+
499
+ {/* Employees */}
500
+ <Box>
501
+ <Typography variant="h6" sx={{ mb: 2 }}>Employee List</Typography>
52
502
  <ReferenceManyField reference="Employee" target="OnLoanDepartmentId" addLabel={false} pagination={<Pagination />}>
53
503
  <Datagrid rowClick="show">
54
504
  <TextField source="LastName" label="Last Name" />
@@ -58,12 +508,33 @@ export const DepartmentShow = (props) => (
58
508
  <DeleteButton />
59
509
  </Datagrid>
60
510
  </ReferenceManyField>
61
- <AddEmployeeButton />
62
- </Tab>
63
- </TabbedShowLayout>
511
+ </Box>
512
+ </SimpleShowLayout>
64
513
  </Show>
65
514
  );
66
515
 
516
+ // Custom Add Sub-Department Button
517
+ const AddSubDepartmentButton = () => {
518
+ const record = useRecordContext();
519
+ const redirect = useRedirect();
520
+
521
+ const handleClick = () => {
522
+ redirect(`/Department/create?source=${encodeURIComponent(JSON.stringify({ DepartmentId: record?.id }))}`);
523
+ };
524
+
525
+ return (
526
+ <Button
527
+ variant="contained"
528
+ color="primary"
529
+ startIcon={<AddIcon />}
530
+ onClick={handleClick}
531
+ sx={{ mt: 2 }}
532
+ >
533
+ Add Sub-Department
534
+ </Button>
535
+ );
536
+ };
537
+
67
538
  // Custom Add Employee Button
68
539
  const AddEmployeeButton = () => {
69
540
  const record = useRecordContext();
@@ -105,6 +576,13 @@ export const DepartmentCreate = (props) => (
105
576
  <NumberInput source="SecurityLevel" label="Security Level" fullWidth />
106
577
  </Box>
107
578
  </Grid>
579
+ <Grid item xs={12} sm={6} md={4}>
580
+ <Box sx={{ p: 1 }}>
581
+ <ReferenceInput source="DepartmentId" reference="Department" label="Parent Department">
582
+ <SelectInput optionText="DepartmentName" />
583
+ </ReferenceInput>
584
+ </Box>
585
+ </Grid>
108
586
  </Grid>
109
587
  </Box>
110
588
  </SimpleForm>
@@ -130,15 +608,24 @@ export const DepartmentEdit = (props) => (
130
608
  <NumberInput source="SecurityLevel" label="Security Level" fullWidth />
131
609
  </Box>
132
610
  </Grid>
611
+ <Grid item xs={12} sm={6} md={4}>
612
+ <Box sx={{ p: 1 }}>
613
+ <ReferenceInput source="DepartmentId" reference="Department" label="Parent Department">
614
+ <SelectInput optionText="DepartmentName" />
615
+ </ReferenceInput>
616
+ </Box>
617
+ </Grid>
133
618
  </Grid>
134
619
  </Box>
135
620
  </SimpleForm>
136
621
  </Edit>
137
622
  );
138
623
 
139
- export default {
624
+ const DepartmentResource = {
140
625
  list: DepartmentList,
141
626
  show: DepartmentShow,
142
627
  create: DepartmentCreate,
143
628
  edit: DepartmentEdit,
144
- };
629
+ };
630
+
631
+ export default DepartmentResource;