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.
- api_logic_server_cli/api_logic_server.py +2 -2
- api_logic_server_cli/api_logic_server_info.yaml +3 -3
- api_logic_server_cli/genai/genai_svcs.py +4 -3
- api_logic_server_cli/manager.py +7 -5
- 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/examples/mcp_context_results.txt +142 -0
- api_logic_server_cli/prototypes/base/integration/mcp/mcp_client_executor.py +65 -29
- api_logic_server_cli/prototypes/manager/system/Manager_workspace.code-workspace +3 -3
- api_logic_server_cli/prototypes/manager/system/genai/app_templates/app_learning/Admin-App-Resource-Learning-Prompt.md +3 -2
- api_logic_server_cli/prototypes/manager/system/genai/app_templates/app_learning/Admin-App-js-Learning-Prompt.md +4 -14
- 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/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.35.dist-info → apilogicserver-15.0.38.dist-info}/METADATA +1 -1
- {apilogicserver-15.0.35.dist-info → apilogicserver-15.0.38.dist-info}/RECORD +44 -23
- api_logic_server_cli/prototypes/base/docs/training/admin_app_unused.md +0 -156
- {apilogicserver-15.0.35.dist-info → apilogicserver-15.0.38.dist-info}/WHEEL +0 -0
- {apilogicserver-15.0.35.dist-info → apilogicserver-15.0.38.dist-info}/entry_points.txt +0 -0
- {apilogicserver-15.0.35.dist-info → apilogicserver-15.0.38.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-15.0.35.dist-info → apilogicserver-15.0.38.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
from database import models
|
|
2
|
+
import logging
|
|
3
|
+
from safrs import jsonapi_attr
|
|
4
|
+
from sqlalchemy.orm import relationship, remote, foreign
|
|
5
|
+
from functools import wraps # This convenience func preserves name and docstring
|
|
6
|
+
import decimal as decimal
|
|
7
|
+
from sqlalchemy import extract, func
|
|
8
|
+
from flask import request, jsonify
|
|
9
|
+
from safrs import jsonapi_rpc, SAFRSAPI
|
|
10
|
+
import safrs
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
Graphics methods for database classes, created when:
|
|
14
|
+
* `als genai create` contains prompts like: 'Graph Sales by Category', etc.
|
|
15
|
+
* `als add-graphics` --using the docs/graphics directory
|
|
16
|
+
|
|
17
|
+
Called by api/api_discovery/dashboard_services.py when admin app loaded
|
|
18
|
+
|
|
19
|
+
You typically do not alter this file - rebuilt on als genai--graphics.
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
app_logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def add_method(cls):
|
|
27
|
+
"""
|
|
28
|
+
Decorator to add method to class, e.g., db class group by query method
|
|
29
|
+
|
|
30
|
+
Thanks to: https://mgarod.medium.com/dynamically-add-a-method-to-a-class-in-python-c49204b85bd6
|
|
31
|
+
"""
|
|
32
|
+
def decorator(func):
|
|
33
|
+
@wraps(func)
|
|
34
|
+
def wrapper(self, *args, **kwargs):
|
|
35
|
+
return func(*args, **kwargs)
|
|
36
|
+
|
|
37
|
+
setattr(cls, func.__name__, wrapper)
|
|
38
|
+
# Note we are not binding func, but wrapper which accepts self but does exactly the same as func
|
|
39
|
+
return func # returning func means func can still be used normally
|
|
40
|
+
return decorator
|
|
41
|
+
|
|
42
|
+
##############################
|
|
43
|
+
# generated services follow
|
|
44
|
+
##############################
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
@add_method(models.Category)
|
|
50
|
+
@jsonapi_rpc(http_methods=['GET', 'OPTIONS'])
|
|
51
|
+
def sales_by_category(*args, **kwargs):
|
|
52
|
+
"""
|
|
53
|
+
Complex query with multiple joins, for graphics, from 'Graph Sales by Category', etc.
|
|
54
|
+
Test with Swagger.
|
|
55
|
+
"""
|
|
56
|
+
if request.method == 'OPTIONS':
|
|
57
|
+
return jsonify({ "result": "ok" })
|
|
58
|
+
|
|
59
|
+
from database.models import Category, Product, OrderDetail, Order
|
|
60
|
+
db = safrs.DB
|
|
61
|
+
session = db.session # sqlalchemy.orm.scoping.scoped_session
|
|
62
|
+
# Security.set_user_sa() # an endpoint that requires no auth header (see also @bypass_security)
|
|
63
|
+
|
|
64
|
+
# SQLAlchemy query
|
|
65
|
+
query = sales_by_category = ((session.query(Category.CategoryName, func.sum(OrderDetail.Quantity * OrderDetail.UnitPrice * (1 - OrderDetail.Discount))
|
|
66
|
+
.label("TotalSales"))
|
|
67
|
+
.join(Product, Category.Id == Product.CategoryId)
|
|
68
|
+
.join(OrderDetail, Product.Id == OrderDetail.ProductId)
|
|
69
|
+
.join(Order, OrderDetail.OrderId == Order.Id)
|
|
70
|
+
.filter(Order.ShippedDate.is_not(None))
|
|
71
|
+
.group_by(Category.CategoryName)
|
|
72
|
+
.order_by(func.sum(OrderDetail.Quantity * OrderDetail.UnitPrice * (1 - OrderDetail.Discount))
|
|
73
|
+
.desc())))
|
|
74
|
+
# Execute query and fetch results
|
|
75
|
+
results = query.all()
|
|
76
|
+
from decimal import Decimal
|
|
77
|
+
columns = ['Category Name' , 'Total Sales']
|
|
78
|
+
results = [{columns[0]: row[0], columns[1]: round(float(row[1]), 2)} for row in results]
|
|
79
|
+
title = 'Sales by Category'
|
|
80
|
+
graph_type = 'Bar'.lower()
|
|
81
|
+
json_results = {
|
|
82
|
+
"results": results,
|
|
83
|
+
"columns": columns,
|
|
84
|
+
"title": title,
|
|
85
|
+
"chart_type": graph_type,
|
|
86
|
+
"xAxis": columns[0],
|
|
87
|
+
"yAxis": columns[1],
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return json_results
|
|
91
|
+
@classmethod
|
|
92
|
+
@add_method(models.Category)
|
|
93
|
+
@jsonapi_rpc(http_methods=['GET', 'OPTIONS'])
|
|
94
|
+
def number_of_sales_per_category(*args, **kwargs):
|
|
95
|
+
"""
|
|
96
|
+
Complex query with multiple joins, for graphics, from 'Graph Sales by Category', etc.
|
|
97
|
+
Test with Swagger.
|
|
98
|
+
"""
|
|
99
|
+
if request.method == 'OPTIONS':
|
|
100
|
+
return jsonify({ "result": "ok" })
|
|
101
|
+
|
|
102
|
+
from database.models import Category, Product, OrderDetail, Order
|
|
103
|
+
db = safrs.DB
|
|
104
|
+
session = db.session # sqlalchemy.orm.scoping.scoped_session
|
|
105
|
+
# Security.set_user_sa() # an endpoint that requires no auth header (see also @bypass_security)
|
|
106
|
+
|
|
107
|
+
# SQLAlchemy query
|
|
108
|
+
query = number_of_sales_per_category = ((session.query(Category.CategoryName, func.count(Order.Id)
|
|
109
|
+
.label("NumberOfSales"))
|
|
110
|
+
.join(Product, Product.CategoryId == Category.Id)
|
|
111
|
+
.join(OrderDetail, OrderDetail.ProductId == Product.Id)
|
|
112
|
+
.join(Order, Order.Id == OrderDetail.OrderId)
|
|
113
|
+
.filter(Order.ShippedDate.is_not(None))
|
|
114
|
+
.group_by(Category.CategoryName)
|
|
115
|
+
.order_by(func.count(Order.Id)
|
|
116
|
+
.desc())))
|
|
117
|
+
# Execute query and fetch results
|
|
118
|
+
results = query.all()
|
|
119
|
+
from decimal import Decimal
|
|
120
|
+
columns = ['Category Name' , 'Number of Sales']
|
|
121
|
+
results = [{columns[0]: row[0], columns[1]: round(float(row[1]), 2)} for row in results]
|
|
122
|
+
title = 'Number of Sales Per Category'
|
|
123
|
+
graph_type = 'Bar'.lower()
|
|
124
|
+
json_results = {
|
|
125
|
+
"results": results,
|
|
126
|
+
"columns": columns,
|
|
127
|
+
"title": title,
|
|
128
|
+
"chart_type": graph_type,
|
|
129
|
+
"xAxis": columns[0],
|
|
130
|
+
"yAxis": columns[1],
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return json_results
|
|
134
|
+
@classmethod
|
|
135
|
+
@add_method(models.Order)
|
|
136
|
+
@jsonapi_rpc(http_methods=['GET', 'OPTIONS'])
|
|
137
|
+
def count_orders_by_month(*args, **kwargs):
|
|
138
|
+
"""
|
|
139
|
+
Complex query with multiple joins, for graphics, from 'Graph Sales by Category', etc.
|
|
140
|
+
Test with Swagger.
|
|
141
|
+
"""
|
|
142
|
+
if request.method == 'OPTIONS':
|
|
143
|
+
return jsonify({ "result": "ok" })
|
|
144
|
+
|
|
145
|
+
from database.models import Order
|
|
146
|
+
db = safrs.DB
|
|
147
|
+
session = db.session # sqlalchemy.orm.scoping.scoped_session
|
|
148
|
+
# Security.set_user_sa() # an endpoint that requires no auth header (see also @bypass_security)
|
|
149
|
+
|
|
150
|
+
# SQLAlchemy query
|
|
151
|
+
query = count_orders_by_month = ((session.query(func.strftime('%Y-%m', func.date(Order.OrderDate))
|
|
152
|
+
.label("OrderMonth"), func.count(Order.Id)
|
|
153
|
+
.label("OrderCount"))
|
|
154
|
+
.filter(Order.OrderDate.is_not(None))
|
|
155
|
+
.group_by(func.strftime('%Y-%m', func.date(Order.OrderDate)))
|
|
156
|
+
.order_by(func.strftime('%Y-%m', func.date(Order.OrderDate)))))
|
|
157
|
+
# Execute query and fetch results
|
|
158
|
+
results = query.all()
|
|
159
|
+
from decimal import Decimal
|
|
160
|
+
columns = ['Month' , 'Order Count']
|
|
161
|
+
results = [{columns[0]: row[0], columns[1]: round(float(row[1]), 2)} for row in results]
|
|
162
|
+
title = 'Order Count by Month'
|
|
163
|
+
graph_type = 'Line'.lower()
|
|
164
|
+
json_results = {
|
|
165
|
+
"results": results,
|
|
166
|
+
"columns": columns,
|
|
167
|
+
"title": title,
|
|
168
|
+
"chart_type": graph_type,
|
|
169
|
+
"xAxis": columns[0],
|
|
170
|
+
"yAxis": columns[1],
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return json_results
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
const sla_doc =
|
|
2
2
|
'<div class="MuiTypography-root jss4" style="color: rgba(0, 0, 0, 0.66)">' +
|
|
3
3
|
'<div style="text-align:center">' +
|
|
4
|
+
'<div class="dashboard-iframe">' +
|
|
5
|
+
|
|
6
|
+
'<iframe id="iframeTargetDashboard" src="http://localhost:5656/dashboard" style="flex: 1; border: none; width: 100%; height: 200px;"></iframe>' +
|
|
7
|
+
|
|
8
|
+
'</div>' +
|
|
4
9
|
'<h2>Welcome to GenAI-Logic/API Logic Server - Sample</h2>' +
|
|
5
10
|
'</div><br>' +
|
|
6
11
|
'<h3><a class="custom" style="color: #3f51b5;" rel="nofollow" href="https://www.genai-logic.com" target="_blank">GenAI-Logic</a> ' +
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Department Tree View Feature
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
The Department component now supports two view modes:
|
|
5
|
+
1. **List View** - Traditional table view showing all departments
|
|
6
|
+
2. **Tree View** - Hierarchical view showing department relationships
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
### View Toggle
|
|
11
|
+
- Switch between List and Tree views using the toggle buttons in the top-right corner
|
|
12
|
+
- List view shows departments in a traditional table format
|
|
13
|
+
- Tree view shows departments in a hierarchical structure
|
|
14
|
+
|
|
15
|
+
### Tree View Functionality
|
|
16
|
+
- **Hierarchical Display**: Shows parent-child relationships between departments
|
|
17
|
+
- **Expandable Nodes**: Click the expand/collapse icons to show/hide sub-departments
|
|
18
|
+
- **Clickable Department Names**: Click on any department name to view its details
|
|
19
|
+
- **Split View**: When a department is selected, its details appear in a panel to the right
|
|
20
|
+
- **Security Level Display**: Shows security level next to each department name
|
|
21
|
+
|
|
22
|
+
### Split View Details Panel
|
|
23
|
+
When a department is clicked in tree view, the right panel shows:
|
|
24
|
+
- Department basic information (Security Level, ID)
|
|
25
|
+
- List of sub-departments (if any)
|
|
26
|
+
- List of employees in that department (up to 5, with count if more)
|
|
27
|
+
- Close button to hide the details panel
|
|
28
|
+
|
|
29
|
+
### Enhanced Forms
|
|
30
|
+
- **Create Department**: Now includes parent department selection
|
|
31
|
+
- **Edit Department**: Can change parent department relationships
|
|
32
|
+
- **Show Department**: Displays parent department information and has tabs for:
|
|
33
|
+
- Sub-Departments: Shows child departments with add button
|
|
34
|
+
- Employee List: Shows employees in this department
|
|
35
|
+
|
|
36
|
+
## Technical Implementation
|
|
37
|
+
|
|
38
|
+
### Dependencies Added
|
|
39
|
+
- `@mui/x-tree-view`: Provides TreeView and TreeItem components
|
|
40
|
+
- Enhanced MUI components for better UI
|
|
41
|
+
|
|
42
|
+
### Key Components
|
|
43
|
+
- `DepartmentTreeView`: Main tree component
|
|
44
|
+
- `DepartmentTreeItem`: Recursive tree item for hierarchy
|
|
45
|
+
- `DepartmentDetails`: Details panel for split view
|
|
46
|
+
- `AddSubDepartmentButton`: Button to create sub-departments
|
|
47
|
+
|
|
48
|
+
### API Integration
|
|
49
|
+
- Uses `useGetList` hook to fetch department hierarchies
|
|
50
|
+
- Filters departments by `DepartmentId` to build tree structure
|
|
51
|
+
- Supports real-time data updates
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
1. Navigate to the Departments section
|
|
55
|
+
2. Use the toggle buttons to switch between List and Tree views
|
|
56
|
+
3. In Tree view:
|
|
57
|
+
- Expand/collapse departments to explore hierarchy
|
|
58
|
+
- Click department names to view details
|
|
59
|
+
- Use the split view to see department information
|
|
60
|
+
- Create sub-departments using the "Add Sub-Department" button
|
|
61
|
+
|
|
62
|
+
## Benefits
|
|
63
|
+
- **Better Organization**: Visualize department hierarchy clearly
|
|
64
|
+
- **Improved Navigation**: Quick access to related departments
|
|
65
|
+
- **Enhanced UX**: Split view allows comparing departments
|
|
66
|
+
- **Efficient Management**: Easy creation of sub-departments
|
|
@@ -5,16 +5,20 @@
|
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@emotion/react": "^11.14.0",
|
|
7
7
|
"@emotion/styled": "^11.14.0",
|
|
8
|
+
"@mui/icons-material": "^7.1.1",
|
|
8
9
|
"@mui/material": "^7.1.1",
|
|
10
|
+
"@mui/x-tree-view": "^8.7.0",
|
|
9
11
|
"@testing-library/dom": "^10.4.0",
|
|
10
12
|
"@testing-library/jest-dom": "^6.6.3",
|
|
11
13
|
"@testing-library/react": "^16.3.0",
|
|
12
14
|
"@testing-library/user-event": "^13.5.0",
|
|
13
15
|
"compare-versions": "^6.1.1",
|
|
14
16
|
"keycloak-js": "^26.2.0",
|
|
17
|
+
"leaflet": "^1.9.4",
|
|
15
18
|
"react": "^19.1.0",
|
|
16
19
|
"react-admin": "^5.8.3",
|
|
17
20
|
"react-dom": "^19.1.0",
|
|
21
|
+
"react-leaflet": "^5.0.0",
|
|
18
22
|
"react-router-dom": "^7.6.2",
|
|
19
23
|
"react-scripts": "5.0.1",
|
|
20
24
|
"url-join": "^5.0.0",
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
|
16
16
|
-->
|
|
17
17
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
|
18
|
+
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
|
19
|
+
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
|
|
20
|
+
crossorigin=""/>
|
|
18
21
|
<!--
|
|
19
22
|
Notice the use of %PUBLIC_URL% in the tags above.
|
|
20
23
|
It will be replaced with the URL of the `public` folder during the build.
|
|
@@ -4,6 +4,8 @@ import { Admin, Resource, Loading } from 'react-admin';
|
|
|
4
4
|
import { jsonapiClient } from './rav4-jsonapi-client/ra-jsonapi-client';
|
|
5
5
|
import { createTheme } from '@mui/material/styles';
|
|
6
6
|
import { useConf, loadHomeConf } from './Config';
|
|
7
|
+
import LandingPage from './LandingPage';
|
|
8
|
+
import CustomLayout from './CustomLayout';
|
|
7
9
|
// End constant imports
|
|
8
10
|
|
|
9
11
|
// Import each resource
|
|
@@ -55,7 +57,12 @@ const App = () => {
|
|
|
55
57
|
const dataProvider = jsonapiClient(conf.api_root, { conf: {} }, null);
|
|
56
58
|
|
|
57
59
|
return (
|
|
58
|
-
<Admin
|
|
60
|
+
<Admin
|
|
61
|
+
dataProvider={dataProvider}
|
|
62
|
+
theme={theme}
|
|
63
|
+
dashboard={LandingPage}
|
|
64
|
+
layout={CustomLayout}
|
|
65
|
+
>
|
|
59
66
|
<Resource
|
|
60
67
|
name="Customer"
|
|
61
68
|
list={CustomerList}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Layout, AppBar } from 'react-admin';
|
|
3
|
+
import { Typography } from '@mui/material';
|
|
4
|
+
|
|
5
|
+
const CustomAppBar = (props) => (
|
|
6
|
+
<AppBar {...props}>
|
|
7
|
+
<Typography variant="h6" color="inherit" sx={{ flex: 1 }}>
|
|
8
|
+
API Logic Server - Northwind Sample
|
|
9
|
+
</Typography>
|
|
10
|
+
</AppBar>
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
const CustomLayout = (props) => (
|
|
14
|
+
<Layout
|
|
15
|
+
{...props}
|
|
16
|
+
appBar={CustomAppBar}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
export default CustomLayout;
|