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.
Files changed (55) hide show
  1. api_logic_server_cli/api_logic_server.py +2 -2
  2. api_logic_server_cli/api_logic_server_info.yaml +2 -2
  3. api_logic_server_cli/genai/genai_svcs.py +4 -3
  4. api_logic_server_cli/prototypes/base/.copilot-instructions.md +10 -0
  5. api_logic_server_cli/prototypes/base/.vscode/.copilot-instructions.md +178 -0
  6. api_logic_server_cli/prototypes/base/README_PROJECT.md +43 -0
  7. api_logic_server_cli/prototypes/base/api_logic_server_run.py +20 -8
  8. api_logic_server_cli/prototypes/base/docs/training/react_map.prompt.md +13 -0
  9. api_logic_server_cli/prototypes/base/docs/training/react_tree.prompt.md +10 -0
  10. api_logic_server_cli/prototypes/base/integration/mcp/readme-mcp.md +9 -0
  11. api_logic_server_cli/prototypes/base/logic/logic_discovery/readme_logic_discovery.md +9 -0
  12. api_logic_server_cli/prototypes/base/logic/logic_discovery/use_case.py +27 -0
  13. api_logic_server_cli/prototypes/base/logic/{readme_declare_logic.md → readme_logic.md} +70 -1
  14. api_logic_server_cli/prototypes/base/readme.md +30 -5
  15. api_logic_server_cli/prototypes/base/security/readme_security.md +17 -0
  16. api_logic_server_cli/prototypes/manager/.copilot-instructions.md +13 -0
  17. api_logic_server_cli/prototypes/manager/.vscode/.copilot-instructions.md +58 -0
  18. api_logic_server_cli/prototypes/manager/.vscode/ApiLogicServer.code-workspace +2 -2
  19. api_logic_server_cli/prototypes/manager/README.md +13 -1
  20. api_logic_server_cli/prototypes/manager/system/Manager_workspace.code-workspace +3 -3
  21. api_logic_server_cli/prototypes/nw/api/api_discovery/authentication_expose_api_models.py +53 -0
  22. api_logic_server_cli/prototypes/nw/api/api_discovery/auto_discovery.py +27 -0
  23. api_logic_server_cli/prototypes/nw/api/api_discovery/count_orders_by_month.html +76 -0
  24. api_logic_server_cli/prototypes/nw/api/api_discovery/count_orders_by_month.sql +1 -0
  25. api_logic_server_cli/prototypes/nw/api/api_discovery/dashboard_services.py +143 -0
  26. api_logic_server_cli/prototypes/nw/api/api_discovery/mcp_discovery.py +97 -0
  27. api_logic_server_cli/prototypes/nw/api/api_discovery/new_service.py +21 -0
  28. api_logic_server_cli/prototypes/nw/api/api_discovery/newer_service.py +21 -0
  29. api_logic_server_cli/prototypes/nw/api/api_discovery/number_of_sales_per_category.html +76 -0
  30. api_logic_server_cli/prototypes/nw/api/api_discovery/number_of_sales_per_category.sql +1 -0
  31. api_logic_server_cli/prototypes/nw/api/api_discovery/ontimize_api.py +495 -0
  32. api_logic_server_cli/prototypes/nw/api/api_discovery/sales_by_category.html +76 -0
  33. api_logic_server_cli/prototypes/nw/api/api_discovery/sales_by_category.sql +1 -0
  34. api_logic_server_cli/prototypes/nw/api/api_discovery/system.py +77 -0
  35. api_logic_server_cli/prototypes/nw/database/database_discovery/graphics_services.py +173 -0
  36. api_logic_server_cli/prototypes/nw/ui/admin/home.js +5 -0
  37. api_logic_server_cli/prototypes/nw/ui/reference_react_app/DEPARTMENT_TREE_VIEW.md +66 -0
  38. api_logic_server_cli/prototypes/nw/ui/reference_react_app/README.md +21 -4
  39. api_logic_server_cli/prototypes/nw/ui/reference_react_app/package.json +4 -0
  40. api_logic_server_cli/prototypes/nw/ui/reference_react_app/public/index.html +3 -0
  41. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/App.js +8 -1
  42. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/CustomLayout.js +20 -0
  43. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/Department.js +511 -24
  44. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/DepartmentTree.js +147 -0
  45. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/Employee.js +230 -18
  46. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/LandingPage.js +264 -0
  47. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/Supplier.js +359 -121
  48. api_logic_server_cli/prototypes/nw/ui/reference_react_app/src/index.js +1 -0
  49. {apilogicserver-15.0.37.dist-info → apilogicserver-15.0.40.dist-info}/METADATA +1 -1
  50. {apilogicserver-15.0.37.dist-info → apilogicserver-15.0.40.dist-info}/RECORD +54 -25
  51. api_logic_server_cli/prototypes/base/docs/training/admin_app_unused.md +0 -156
  52. {apilogicserver-15.0.37.dist-info → apilogicserver-15.0.40.dist-info}/WHEEL +0 -0
  53. {apilogicserver-15.0.37.dist-info → apilogicserver-15.0.40.dist-info}/entry_points.txt +0 -0
  54. {apilogicserver-15.0.37.dist-info → apilogicserver-15.0.40.dist-info}/licenses/LICENSE +0 -0
  55. {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 EXACTLY)
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
- <List filters={<EmployeeFilter />} {...props} sort={{ field: 'LastName', order: 'ASC' }} pagination={<Pagination rowsPerPageOptions={[5, 10, 25]} showFirstLastButtons />}>
24
- <Datagrid rowClick="show">
25
- <TextField source="LastName" label="Last Name" />
26
- <TextField source="FirstName" label="First Name" />
27
- <EmailField source="Email" label="Email" />
28
- <NumberField source="Salary" label="Salary" options={{ style: 'currency', currency: 'USD'}} />
29
- <ReferenceField source="WorksForDepartmentId" reference="Department" label="Department">
30
- <TextField source="DepartmentName" />
31
- </ReferenceField>
32
- <EditButton />
33
- <DeleteButton />
34
- <ShowButton />
35
- </Datagrid>
36
- </List>
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>