Skip to content

Commit

Permalink
refactors to use mogwai
Browse files Browse the repository at this point in the history
  • Loading branch information
WolfgangFahl committed Nov 16, 2024
1 parent b9cbebd commit d777c75
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 78 deletions.
2 changes: 1 addition & 1 deletion crm/crm_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from ngwidgets.cmd import WebserverCmd

from crm.crm_core import CRM
from crm.em import CRM
from crm.crm_web import CrmWebServer


Expand Down
180 changes: 113 additions & 67 deletions crm/crm_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,91 +3,101 @@
@author: wf
"""
import os
import i18n
from crm.i18n_config import I18nConfig
from ngwidgets.input_webserver import InputWebserver, InputWebSolution
from ngwidgets.webserver import WebserverConfig
from nicegui import Client, ui, run
from ngwidgets.lod_grid import ListOfDictsGrid, GridConfig

from crm.crm_core import CRM, Organizations, Persons
from crm.em import CRM
from crm.db import DB
from crm.crm_core import Organizations, Persons
from crm.version import Version

class EntityIndex:
def __init__(self):

from lodstorage.persistent_log import Log
from mogwai.schema.graph_schema import GraphSchema
from mogwai.web.node_view import NodeTableView, NodeView, NodeViewConfig
from mogwai.core.mogwaigraph import MogwaiGraph, MogwaiGraphConfig

class CrmSolution(InputWebSolution):
"""
Customer Relationship Management solution
"""
def __init__(self, webserver: "CrmWebServer", client: Client):
super().__init__(webserver, client)
self.organizations = Organizations()
self.persons = Persons()
self.org_lod = []
self.person_lod = []
self.org_lod_grid = None
self.person_lod_grid = None

def doUpdateEntities(self):
"""
update entities
"""
try:
with self.header_row:
self.org_count_label.set_text(f"Organizations: {len(self.org_lod)}")
self.person_count_label.set_text(f"Persons: {len(self.person_lod)}")

if self.org_lod_grid:
self.org_lod_grid.load_lod(self.org_lod)
if self.person_lod_grid:
self.person_lod_grid.load_lod(self.person_lod)

except Exception as ex:
self.handle_exception(ex)
self.log=self.webserver.log
self.graph=self.webserver.graph
self.schema=self.webserver.schema

async def updateEntities(self):
await run.io_bound(self.doUpdateEntities)
def prepare_ui(self):
pass

def setup_lod_grid(self, lod, key_col: str = "Id"):
def configure_menu(self):
"""
setup the list of dicts grid
configure additional non-standard menu entries
"""
grid_config = GridConfig(
key_col=key_col,
editable=True,
multiselect=True,
with_buttons=False,
debug=self.args.debug
# Sorting the node types by display_order
sorted_node_types = sorted(
self.schema.node_type_configs.items(),
key=lambda item: item[1].display_order,
)
lod_grid = ListOfDictsGrid(lod=lod, config=grid_config)
lod_grid.set_checkbox_selection(key_col)
return lod_grid

def prepare_ui(self):
pass
for node_type_name, node_type in sorted_node_types: # label e.g. project_list
label_i18nkey = f"{node_type.label.lower()}_list"
label = i18n.t(label_i18nkey)
path = f"/nodes/{node_type_name}"
self.link_button(label, path, node_type.icon, new_tab=False)

async def home(self):
"""
provide the main content page

async def show_nodes(self, node_type: str):
"""
def setup_home():
with ui.row() as self.header_row:
self.org_count_label = ui.label()
self.person_count_label = ui.label()
show nodes of the given type
with ui.tabs() as tabs:
ui.tab("Organizations")
ui.tab("Persons")
Args:
node_type(str): the type of nodes to show
"""

with ui.tab_panels(tabs, value="Organizations"):
with ui.tab_panel("Organizations"):
self.org_lod_grid = self.setup_lod_grid(self.org_lod, key_col="Id")
with ui.tab_panel("Persons"):
self.person_lod_grid = self.setup_lod_grid(self.person_lod, key_col="Id")
def show():
try:
config = NodeViewConfig(
solution=self,
graph=self.graph,
schema=self.schema,
node_type=node_type,
)
if not config.node_type_config:
ui.label(f"{i18n.t('invalid_node_type')}: {node_type}")
return
node_table_view = NodeTableView(config=config)
node_table_view.setup_ui()
except Exception as ex:
self.handle_exception(ex)

await self.setup_content_div(show)

async def show_node(self, node_type: str, node_id: str):
"""
show the given node
"""

ui.timer(0, self.updateEntities, once=True)
def show():
config = NodeViewConfig(
solution=self, graph=self.graph, schema=self.schema, node_type=node_type
)
if not config.node_type_config:
ui.label(f"{i18n.t('invalid_node_type')}: {node_type}")
return
# default view is the general NodeView
view_class = NodeView
# unless there is a specialization configured
if config.node_type_config._viewclass:
view_class = config.node_type_config._viewclass
node_view = view_class(config=config, node_id=node_id)
node_view.setup_ui()
pass

await self.setup_content_div(show)

await self.setup_content_div(setup_home)

class CrmWebServer(InputWebserver):
"""
Expand All @@ -107,10 +117,46 @@ def get_config(cls) -> WebserverConfig:
return server_config

def __init__(self):
lods= {
org:
}
self.org_lod = self.organizations.from_json_file()
self.person_lod = self.persons.from_json_file()
super().__init__(config=CrmWebServer.get_config())

self.log = Log()
config=MogwaiGraphConfig(name_field="_node_name", index_config="minimal")
self.graph = MogwaiGraph(config=config)

@ui.page("/nodes/{node_type}")
async def show_nodes(client: Client, node_type: str):
"""
show the nodes of the given type
"""
await self.page(client, CrmSolution.show_nodes, node_type)

@ui.page("/node/{node_type}/{node_id}")
async def node(client: Client, node_type: str, node_id: str):
"""
show the node with the given node_id
"""
await self.page(client, CrmSolution.show_node, node_type, node_id)

def configure_run(self):
"""
configure with args
"""
#args = self.args
I18nConfig.config()

InputWebserver.configure_run(self)
module_path = os.path.dirname(os.path.abspath(__file__))
yaml_path = os.path.join(module_path, "resources", "crm-schema.yaml")

self.schema = GraphSchema.load(yaml_path=yaml_path)
self.schema.add_to_graph(self.graph)
self.db = DB()

for entity_class in (Organizations, Persons):
entities = entity_class()
lod = entities.from_db(self.db)
for record in lod:
_node = self.graph.add_labeled_node(
entities.entity_name,
name=entities.entity_name,
properties=record
)
27 changes: 27 additions & 0 deletions crm/i18n_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""
Created on 2024-11-16
@author: wf
"""

import os

import i18n


class I18nConfig:
"""
Internationalization module configuration
"""

@classmethod
def config(cls, debug: bool = False):
module_path = os.path.dirname(os.path.abspath(__file__))
translations_path = os.path.join(module_path, "resources", "i18n")
if debug:
print(f"Loading translations from: {translations_path}")
print(f"Files in directory: {os.listdir(translations_path)}")
i18n.load_path.append(translations_path)
i18n.set("filename_format", "{locale}.{format}")
i18n.set("file_format", "yaml")
i18n.set("fallback", "en")
38 changes: 38 additions & 0 deletions crm/resources/crm-schema.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#
# CRM graph schema
#
# WF 2024-11-16
#
node_id_type_name: str

#
# configuration of available node types
#
node_type_configs:
NodeTypeConfig:
label: NodeTypeConfig
# https://fonts.google.com/icons?icon.set=Material+Icons
icon: schema
key_field: label
dataclass_name: mogwai.schema.graph_schema.NodeTypeConfig
display_name: Node Type
display_order: 40
description: Configuration for a graph node type

Organization:
label: Organization
icon: business
key_field: name
dataclass_name: crm.crm_core.Organization
display_order: 10
display_name: Organization
description: An Organization

Person:
label: Person
icon: person
key_field: name
dataclass_name: crm.crm_core.Person
display_order: 10
display_name: Person
description: A person
8 changes: 8 additions & 0 deletions crm/resources/i18n/de.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#
# Internationalization of crm
# WF 2014-10-21
#
de:
person_list: "Personen"
organization_list: "Organizationen"
nodetypeconfig_list: "Knoten"
8 changes: 8 additions & 0 deletions crm/resources/i18n/en.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#
# Internationalization for crm
# WF 2014-10-21
#
en:
person_list: "Persons"
organization_list: "Organizations"
nodetypeconfig_list: "Nodes"
5 changes: 0 additions & 5 deletions crm/smart_crm.py

This file was deleted.

2 changes: 1 addition & 1 deletion crm/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Version:
name = "niceSmartCRM"
version = crm.__version__
date = "2024-01-12"
updated = "2024-01-12"
updated = "2024-11-16"
description = "nicegui based Customer Relationship Management"

authors = "Wolfgang Fahl"
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ readme = "README.md"
license = {text = "Apache-2.0"}
dependencies = [
# https://github.com/WolfgangFahl/nicegui_widgets
"ngwidgets>=0.17.2",
"ngwidgets>=0.19.4",
# https://pypi.org/project/dataclasses-json/
"dataclasses-json>=0.6.1",
# https://github.com/trentm/python-markdown2
Expand All @@ -29,6 +29,7 @@ dependencies = [
"PyYAML>=6.0.1",
# https://pypi.org/project/linkml/
"linkml>=1.6.8"
#
]

requires-python = ">=3.9"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_crm_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class TestCRM(Basetest):
test CRM
"""

def setUp(self, debug=False, profile=True):
def setUp(self, debug=True, profile=True):
Basetest.setUp(self, debug=debug, profile=profile)
self.db = DB()

Expand Down
6 changes: 4 additions & 2 deletions tests/test_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class TestDB(Basetest):
test Database access layer
"""

def setUp(self, debug=False, profile=True):
def setUp(self, debug=True, profile=True):
Basetest.setUp(self, debug=debug, profile=profile)
self.db = DB()

Expand All @@ -41,4 +41,6 @@ def test_show_tables(self):
"""
test showing all tables
"""
_results = self.check_query("SHOW TABLES", 25)
results = self.check_query("SHOW TABLES", 25)
if self.debug:
print(results)

0 comments on commit d777c75

Please sign in to comment.