Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
dd53ea4
start working on gantt + start date
jafranc Oct 17, 2025
a291921
filter only Solver event (to start with)
jafranc Oct 19, 2025
008c3aa
start wiring in picked date
jafranc Oct 19, 2025
86eaba9
more usable deck for TL
jafranc Oct 19, 2025
df12876
wip import new widgets
jafranc Oct 21, 2025
099af18
wip / first display
jafranc Oct 24, 2025
a2872a2
first working version
jafranc Oct 26, 2025
4045ae8
bind update
jafranc Oct 26, 2025
3e0479a
working
jafranc Oct 27, 2025
89d2abc
working version of the widget
jafranc Oct 27, 2025
ac0bd7a
some more clean-up
jafranc Oct 27, 2025
50ac895
rid of old gantt for dev-version
jafranc Oct 27, 2025
e9d5cd2
adjusting to real deck
jafranc Oct 27, 2025
5030123
working - start including start date logic
jafranc Oct 28, 2025
77ecf0f
solution to small extend tasks
jafranc Oct 28, 2025
8361f5d
working version
jafranc Oct 29, 2025
b2cf7a8
demo version
jafranc Oct 30, 2025
854af27
clean-up
jafranc Oct 30, 2025
2508a4f
fix clean up
jafranc Oct 30, 2025
a74da1c
wip
jafranc Oct 31, 2025
5c739b3
fix if is a list crash
jafranc Nov 2, 2025
731d33f
wip
jafranc Nov 3, 2025
82c2e40
fix typos in paths
jafranc Nov 4, 2025
9086b05
fix connection to file repr
jafranc Nov 4, 2025
93c9b3a
adding freq
jafranc Nov 4, 2025
11f0d95
fix update in inspector
jafranc Nov 4, 2025
e333e8a
some idea
jafranc Nov 4, 2025
ef99e06
fix toml
jafranc Nov 6, 2025
3f3bb47
Merge branch 'jafranc/fix/trame-timeline' of https://github.com/GEOS-…
jafranc Nov 6, 2025
3a8c804
clean up timeline
jafranc Nov 10, 2025
b93fc5c
continue discard algo
jafranc Nov 10, 2025
70fb5a4
maybe better
jafranc Nov 10, 2025
9ab2118
Merge branch 'jafranc/fix/trame-timeline' of https://github.com/GEOS-…
jafranc Nov 10, 2025
9f43ebf
cleaning up verbosity-work pushed to other branch
jafranc Nov 10, 2025
c3a4263
more frequency and only available Categories
jafranc Nov 10, 2025
fce2ff4
change freq if avail
jafranc Nov 10, 2025
173da87
name fix
jafranc Nov 12, 2025
a65dded
cleaner
jafranc Nov 12, 2025
dcdfc09
task deletion
jafranc Nov 12, 2025
1268395
output time in seconds
jafranc Nov 12, 2025
157ddf4
fix freq
jafranc Nov 12, 2025
4851904
Merge branch 'main' into jafranc/fix/trame-timeline
jafranc Nov 19, 2025
ac4e890
Merge branch 'main' into jafranc/fix/trame-timeline
jafranc Nov 20, 2025
f68b9bc
Merge branch 'main' into jafranc/fix/trame-timeline
jafranc Dec 10, 2025
60136d1
fix input conversion problem
jafranc Dec 10, 2025
605d27a
ugly but functional
jafranc Dec 10, 2025
4008b1e
float format
jafranc Dec 12, 2025
244b5fd
skip init logic
jafranc Dec 12, 2025
852909b
working with save as
jafranc Dec 15, 2025
0cf99fc
ruffing and yapfing
jafranc Dec 15, 2025
aca9982
add new widget version
jafranc Dec 15, 2025
af98b82
get some space
jafranc Dec 15, 2025
d727a7f
discard debug
jafranc Dec 15, 2025
d56bde4
can write
jafranc Dec 15, 2025
16e26a9
Merge branch 'main' into jafranc/fix/trame-timeline
jafranc Dec 15, 2025
c58cb55
comments and mypi
jafranc Dec 16, 2025
35a0a5c
missed deps
jafranc Dec 16, 2025
163848d
and now with its type
jafranc Dec 16, 2025
f5c6505
last attempt on toml
jafranc Dec 16, 2025
ebc03e6
yapf
jafranc Dec 16, 2025
3b17fb3
devil in spaces
jafranc Dec 16, 2025
89fedba
restore un needed changes
jafranc Dec 16, 2025
3f89f6b
mypi skip for one line
jafranc Dec 16, 2025
324af05
adding types to mypi
jafranc Dec 16, 2025
2191fd4
yapf happy ?
jafranc Dec 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/typing-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
# working-directory: ./${{ matrix.package-name }}
run: |
python -m pip install --upgrade pip
python -m pip install mypy ruff types-PyYAML
python -m pip install mypy ruff types-PyYAML types-pytz

- name: Typing check with mypy
# working-directory: ./${{ matrix.package-name }}
Expand Down
5 changes: 3 additions & 2 deletions geos-trame/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ version = "1.0.0"
description = "Geos Simulation Modeler"
authors = [{name = "GEOS Contributors" }]
maintainers = [{name = "Alexandre Benedicto", email = "[email protected]" },
{name = "Paloma Martinez", email = "[email protected]" }]
{name = "Paloma Martinez", email = "[email protected]" },
{name = "Jacques Franc", email= "[email protected]" }]
license = {text = "Apache-2.0"}
classifiers = [
"Development Status :: 4 - Beta",
Expand Down Expand Up @@ -40,14 +41,14 @@ dependencies = [
"matplotlib==3.9.4",
"trame-matplotlib==2.0.3",
"trame-components==2.4.2",
"trame-gantt==0.1.5",
"mpld3<0.5.11",
"xsdata==24.5",
"xsdata-pydantic[lxml]==24.5",
"pyvista==0.45.2",
"dpath==2.2.0",
"colorcet==3.1.0",
"funcy==2.0",
"pytz==2025.2",
"typing_inspect==0.9.0",
"typing_extensions>=4.12",
"PyYAML",
Expand Down
10 changes: 5 additions & 5 deletions geos-trame/src/geos/trame/app/core.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright 2023-2024 TotalEnergies.
# SPDX-FileContributor: Lionel Untereiner
# SPDX-FileContributor: Lionel Untereiner, Jacques Franc

from trame.ui.vuetify3 import VAppLayout
from trame.decorators import TrameApp
Expand Down Expand Up @@ -111,7 +111,7 @@ def deck_ui( self ) -> None:
cols=10,
order=2,
):
self.timelineEditor = TimelineEditor( source=self.tree, classes="ma-2", style="height: 40%" )
self.timelineEditor = TimelineEditor( source=self.tree, classes="ma-2", style="height: 60%" )
with vuetify.VRow( classes="mb-6 fill-height", ):

with vuetify.VCol(
Expand All @@ -121,7 +121,7 @@ def deck_ui( self ) -> None:
self.deckEditor = DeckEditor(
source=self.tree,
classes="ma-2",
style="flex: 1; height: 100%;",
style="height: 100%;",
)

with vuetify.VCol(
Expand All @@ -133,13 +133,13 @@ def deck_ui( self ) -> None:
region_viewer=self.region_viewer,
well_viewer=self.well_viewer,
classes="ma-2",
style="flex: 1; height: 60%; width: 100%;",
style="height: 60%; width: 100%;",
)

self.deckPlotting = DeckPlotting(
source=self.tree,
classes="ma-2",
style="flex: 1; height: 40%; width: 100%;",
style="height: 40%; width: 100%;",
)

def build_ui( self ) -> None:
Expand Down
53 changes: 48 additions & 5 deletions geos-trame/src/geos/trame/app/deck/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
import os
from collections import defaultdict
from typing import Any
from datetime import timedelta, datetime

import dpath
import funcy
from pydantic import BaseModel

from xsdata.formats.dataclass.parsers.config import ParserConfig
from xsdata.formats.dataclass.serializers.config import SerializerConfig
from xsdata.utils import text
from xsdata_pydantic.bindings import DictDecoder, XmlContext, XmlSerializer
from xsdata_pydantic.bindings import DictDecoder, XmlContext, XmlSerializer, DictEncoder

from trame_server.controller import Controller
from trame_simput import get_simput_manager
Expand All @@ -21,6 +23,12 @@
from geos.trame.schema_generated.schema_mod import Problem, Included, File, Functions
from geos.trame.app.utils.file_utils import normalize_path, format_xml

import logging

date_fmt = "%Y-%m-%d"
logger = logging.getLogger( "tree" )
logger.setLevel( logging.ERROR )


class DeckTree( object ):
"""A tree that represents a deck file along with all the available blocks and parameters."""
Expand All @@ -36,6 +44,8 @@ def __init__( self, sm_id: str | None = None, ctrl: Controller = None, **kwargs:
self.input_has_errors = False
self._sm_id = sm_id
self._ctrl = ctrl
self.world_origin_time = datetime( 1924, 3, 28 ).strftime( date_fmt ) # Total start date !!
self.registered_targets: dict = {}

def set_input_file( self, input_filename: str ) -> None:
"""Set a new input file.
Expand Down Expand Up @@ -79,6 +89,12 @@ def update( self, path: str, key: str, value: Any ) -> None:
assert self.input_file is not None and self.input_file.pb_dict is not None
self.input_file.pb_dict = funcy.set_in( self.input_file.pb_dict, new_path, value )

def drop( self, path: str ) -> None:
"""Remove in the tree."""
new_path = [ int( x ) if x.isdigit() else x for x in path.split( "/" ) ]
assert self.input_file is not None and self.input_file.pb_dict is not None
self.input_file.pb_dict = funcy.del_in( self.input_file.pb_dict, new_path )

def _search( self, path: str ) -> list | None:
new_path = path.split( "/" )
if self.input_file is None:
Expand All @@ -99,6 +115,17 @@ def decode( self, path: str ) -> BaseModel | None:
decoder = DictDecoder( context=context, config=ParserConfig() )
return decoder.decode( data[ 0 ] )

@staticmethod
def encode_data( data: BaseModel ) -> dict:
"""Convert a data to a xml serializable file."""
context = XmlContext(
element_name_generator=text.pascal_case,
attribute_name_generator=text.camel_case,
)
encoder = DictEncoder( context=context, config=SerializerConfig( indent=" " ) )
nodeDict: dict = encoder.encode( data )
return nodeDict

@staticmethod
def decode_data( data: dict ) -> Problem:
"""Convert a data to a xml serializable file."""
Expand Down Expand Up @@ -133,12 +160,28 @@ def timeline( self ) -> list[ dict ] | None:
timeline = []
# list root events
global_id = 0
for e in self.input_file.problem.events[ 0 ].periodic_event:
all_periodic_events = self.input_file.problem.events[ 0 ].periodic_event
max_time = self.input_file.problem.events[ 0 ].max_time
for e in all_periodic_events:
self.registered_targets[ e.target.split( '/' )[ -1 ] ] = e.target
e.end_time = max_time if float( e.end_time ) > float( max_time ) else e.end_time
#note here float conversion is used to correctly interpret scientific format
item: dict[ str, str | int ] = {
"id": global_id,
"summary": e.name,
"start_date": e.begin_time,
"id":
global_id,
"name":
e.name,
"start": ( datetime.strptime( self.world_origin_time, date_fmt ) +
timedelta( seconds=float( e.begin_time ) ) ).strftime( date_fmt ),
"end": ( datetime.strptime( self.world_origin_time, date_fmt ) +
timedelta( seconds=float( e.end_time ) ) ).strftime( date_fmt ),
"duration":
str( timedelta( seconds=( float( e.end_time ) - float( e.begin_time ) ) ).days ),
"category":
e.target.split( '/' )[ -1 ],
}
if ( int( float( e.time_frequency ) ) > 0 ):
item[ "freq" ] = timedelta( seconds=float( e.time_frequency ) ).days
timeline.append( item )
global_id = global_id + 1

Expand Down
7 changes: 7 additions & 0 deletions geos-trame/src/geos/trame/app/gantt_chart/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from trame_client.utils.version import get_version

__version__ = get_version( "gantt-chart" )

__all__ = [
"__version__",
]
25 changes: 25 additions & 0 deletions geos-trame/src/geos/trame/app/gantt_chart/module/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from pathlib import Path

# Compute local path to serve
serve_path = str( Path( __file__ ).with_name( "serve" ).resolve() )

# Serve directory for JS/CSS files
serve = { "__gantt_chart": serve_path }

# List of JS files to load (usually from the serve path above)
scripts = [ "__gantt_chart/gantt-chart.umd.js" ]

# List of CSS files to load (usually from the serve path above)
# styles = ["__geos_trame/style.css"]

# List of Vue plugins to install/load
vue_use = [ "GanttLib" ]

# Uncomment to add entries to the shared state
# state = {}


# Optional if you want to execute custom initialization at module load
def setup( app, **kwargs ): # noqa
"""Method called at initialization with possibly some custom keyword arguments."""
pass

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions geos-trame/src/geos/trame/app/gantt_chart/widgets/gantt_chart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from trame_client.widgets.core import AbstractElement
from .. import module

__all__ = [
"Gantt",
]


#will eventually be a dependency, so we'll skip some type checks
class HtmlElement( AbstractElement ):

def __init__( self, _elem_name, children=None, **kwargs ) -> None: # noqa
super().__init__( _elem_name, children, **kwargs ) # noqa
if self.server:
self.server.enable_module( module )


class Gantt( HtmlElement ):
"""Gantt Editor component.

Properties:
tasks
availableCategoriesList

Emit:
taskUpdated.
"""

def __init__( self, **kwargs ) -> None: #noqa
super().__init__(
"GanttChart",
**kwargs,
)
self._attr_names += [ "tasks", "availableCategoriesList" ]
self._event_names += [ "taskUpdated" ]
1 change: 0 additions & 1 deletion geos-trame/src/geos/trame/app/ui/inspector.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ def _on_change( topic: str, ids: list | None = None ) -> None:
if ids is not None and topic == "changed":
for obj_id in ids:
proxy = self.simput_manager.proxymanager.get( obj_id )
#self.tree.decode( obj_id ) # if const function and return not used why ?? to decode context ??
for prop in proxy.edited_property_names:
self.tree.update( obj_id, text.camel_case( prop ), proxy.get_property( prop ) )

Expand Down
Loading