From 68f42f7eb76ef58b9e1263e793b2490a58fd4f9e Mon Sep 17 00:00:00 2001 From: Carson-Shaar <120226019+Carson-Shaar@users.noreply.github.com> Date: Mon, 9 Dec 2024 11:16:29 -0500 Subject: [PATCH 1/2] fix: Add style attribute to all relevant components (#384) --- zt_backend/models/components/autocomplete.py | 1 + zt_backend/models/components/button.py | 27 +++++--- zt_backend/models/components/card.py | 1 + zt_backend/models/components/dataframe.py | 65 ++++++++++++++----- zt_backend/models/components/file_input.py | 16 +++-- zt_backend/models/components/iframe.py | 1 + zt_backend/models/components/image.py | 1 + zt_backend/models/components/matplotlib.py | 15 +++-- zt_backend/models/components/number_input.py | 1 + zt_backend/models/components/range_slider.py | 54 +++++++++------ zt_backend/models/components/rating.py | 1 + zt_backend/models/components/selectbox.py | 1 + zt_backend/models/components/slider.py | 53 +++++++++------ .../models/components/text_area_input.py | 1 + zt_backend/models/components/text_input.py | 1 + 15 files changed, 166 insertions(+), 73 deletions(-) diff --git a/zt_backend/models/components/autocomplete.py b/zt_backend/models/components/autocomplete.py index 30ead98c..90dbad41 100644 --- a/zt_backend/models/components/autocomplete.py +++ b/zt_backend/models/components/autocomplete.py @@ -35,6 +35,7 @@ class Autocomplete(ZTComponent): pre=True, description="Color of the autocomplete component. Can be custom or standard Material color", ) + style: Optional[str] = Field("", description="CSS style to apply to the component") triggerEvent: str = Field( "update:modelValue", description="Trigger event for when to run based on the selected value", diff --git a/zt_backend/models/components/button.py b/zt_backend/models/components/button.py index be2f5f17..14f4e8aa 100644 --- a/zt_backend/models/components/button.py +++ b/zt_backend/models/components/button.py @@ -2,23 +2,34 @@ from zt_backend.models.components.zt_component import ZTComponent from zt_backend.models.state.user_state import UserContext + class Button(ZTComponent): """Standard button UI component""" + component: str = Field("v-btn", description="Vue component name") - value: bool = Field (False, description="Whether the button has been clicked") + value: bool = Field(False, description="Whether the button has been clicked") text: str = Field("Click Me", description="Label displayed on the button") color: str = Field("primary", description="Color of the button") disabled: bool = Field(False, description="If true, the button is disabled") - outlined: bool = Field(False, description="If true, the button will have an outlined style") - triggerEvent: str = Field("click", description="Trigger event to send code to the backend") + outlined: bool = Field( + False, description="If true, the button will have an outlined style" + ) + style: str = Field("", description="CSS style to apply to the component") + triggerEvent: str = Field( + "click", description="Trigger event to send code to the backend" + ) - @validator('value', always=True) + @validator("value", always=True) def get_label_from_global_state(cls, value, values): - id = values.get('id') # Get the id if it exists in the field values + id = values.get("id") # Get the id if it exists in the field values execution_state = UserContext.get_state() try: - if execution_state and id and id in execution_state.component_values: # Check if id exists in global_state - return execution_state.component_values[id] # Return the value associated with id in global_state + if ( + execution_state and id and id in execution_state.component_values + ): # Check if id exists in global_state + return execution_state.component_values[ + id + ] # Return the value associated with id in global_state except Exception as e: pass # Handle exception as needed - return (value) # If id doesn't exist in global_state, return the original value + return value # If id doesn't exist in global_state, return the original value diff --git a/zt_backend/models/components/card.py b/zt_backend/models/components/card.py index 9a5e9a41..cb7ea81b 100644 --- a/zt_backend/models/components/card.py +++ b/zt_backend/models/components/card.py @@ -25,3 +25,4 @@ class Card(ZTComponent): description="Density of the component", ) width: Optional[Union[int, str]] = Field("100%", description="Width of the card") + style: Optional[str] = Field("", description="CSS style to apply to the component") diff --git a/zt_backend/models/components/dataframe.py b/zt_backend/models/components/dataframe.py index f2dfc61e..1d0f4d19 100644 --- a/zt_backend/models/components/dataframe.py +++ b/zt_backend/models/components/dataframe.py @@ -2,41 +2,70 @@ from pydantic import Field, BaseModel import numpy as np from zt_backend.models.components.zt_component import ZTComponent -from typing import List, Dict,Any +from typing import List, Dict, Any class Header(BaseModel): """Header class for the columns of a DataFrame component""" + title: str = Field("", description="Title of the column") align: str = Field("start", description="Alignment of values in the column") - key: str = Field("name", description="Key of the column, must match the key in the items list") + key: str = Field( + "name", description="Key of the column, must match the key in the items list" + ) + class DataFrame(ZTComponent): """DataFrame component for displaying tabluar data""" - component: str = Field("v-data-table", description="Vue component name.") - headers: List[Header] = Field([], description="List of column headers for the DataFrame") - items: List[Dict[str, Any]] = Field([], description="List of items to be displayed in the DataFrame") - multi_sort: bool = Field(True, description="Enable or disable multi-sort on the DataFrame") - search: str = Field("", description="Create a text_input component search = zt.text_input(id='search') before to filter the DataFrame items") + component: str = Field("v-data-table", description="Vue component name.") + headers: List[Header] = Field( + [], description="List of column headers for the DataFrame" + ) + items: List[Dict[str, Any]] = Field( + [], description="List of items to be displayed in the DataFrame" + ) + multi_sort: bool = Field( + True, description="Enable or disable multi-sort on the DataFrame" + ) + style: str = Field("", description="CSS style to apply to the component") + search: str = Field( + "", + description="Create a text_input component search = zt.text_input(id='search') before to filter the DataFrame items", + ) @classmethod - def from_dataframe(cls, df: pd.DataFrame, id: str, multi_sort: bool = True, search: str = ""): + def from_dataframe( + cls, df: pd.DataFrame, id: str, multi_sort: bool = True, search: str = "" + ): """Create a DataFrame component from a pandas DataFrame""" - df = df.replace({np.nan:None}).replace({np.inf:None}).replace({-np.inf:None}) + df = df.replace({np.nan: None}).replace({np.inf: None}).replace({-np.inf: None}) if search: search = search.lower() - df = df[df.astype(str).apply(lambda x: x.str.lower().str.contains(search)).any(axis=1)] + df = df[ + df.astype(str) + .apply(lambda x: x.str.lower().str.contains(search)) + .any(axis=1) + ] headers = [{"title": col, "key": col} for col in df.columns] - items = df.to_dict(orient='records') - return cls(id=id, headers=headers, items=items, multi_sort=multi_sort, search=search) - + items = df.to_dict(orient="records") + return cls( + id=id, headers=headers, items=items, multi_sort=multi_sort, search=search + ) + + def dataframe(df: pd.DataFrame, id: str, multi_sort: bool = True, search: str = ""): """Create a ZT DataFrame component from a pandas DataFrame""" - df = df.replace({np.nan:None}).replace({np.inf:None}).replace({-np.inf:None}) + df = df.replace({np.nan: None}).replace({np.inf: None}).replace({-np.inf: None}) if search: search = search.lower() - df = df[df.astype(str).apply(lambda x: x.str.lower().str.contains(search)).any(axis=1)] - headers = [{"title": col, "key": col} for col in df.columns] - items = df.to_dict(orient='records') - return DataFrame(id=id, headers=headers, items=items, multi_sort=multi_sort, search=search) \ No newline at end of file + df = df[ + df.astype(str) + .apply(lambda x: x.str.lower().str.contains(search)) + .any(axis=1) + ] + headers = [{"title": col, "key": col} for col in df.columns] + items = df.to_dict(orient="records") + return DataFrame( + id=id, headers=headers, items=items, multi_sort=multi_sort, search=search + ) diff --git a/zt_backend/models/components/file_input.py b/zt_backend/models/components/file_input.py index af8e3f6c..06fe5ab7 100644 --- a/zt_backend/models/components/file_input.py +++ b/zt_backend/models/components/file_input.py @@ -5,6 +5,7 @@ from zt_backend.models.components.zt_component import ZTComponent from zt_backend.models.state.user_state import UserContext + class FileInput(ZTComponent): """File input component allowing users to upload files.""" @@ -37,14 +38,19 @@ class FileInput(ZTComponent): counter: Optional[bool] = Field( False, description="If true, shows a file count indicator" ) + style: str = Field("", description="CSS style to apply to the component") - @validator('value', always=True) #TODO: debug and replace with field validator + @validator("value", always=True) # TODO: debug and replace with field validator def get_value_from_global_state(cls, value, values): - id = values['id'] # Get the id if it exists in the field values + id = values["id"] # Get the id if it exists in the field values execution_state = UserContext.get_state() try: - if execution_state and id and id in execution_state.component_values: # Check if id exists in global_state - return execution_state.component_values[id] # Return the value associated with id in global_state + if ( + execution_state and id and id in execution_state.component_values + ): # Check if id exists in global_state + return execution_state.component_values[ + id + ] # Return the value associated with id in global_state except Exception as e: e return value # If id doesn't exist in global_state, return the original value @@ -70,4 +76,4 @@ def get_files(self): for file_name, file_content in self.value.items(): files.append(BytesIO(base64.b64decode(file_content))) - return files \ No newline at end of file + return files diff --git a/zt_backend/models/components/iframe.py b/zt_backend/models/components/iframe.py index d31f5342..d5af56b4 100644 --- a/zt_backend/models/components/iframe.py +++ b/zt_backend/models/components/iframe.py @@ -13,6 +13,7 @@ class iFrame(ZTComponent): height: Union[int, str] = Field("100%", description="Height of the iframe") frameborder: int = Field(0, description="Frame border of the iframe") scrolling: str = Field("auto", description="Scrolling of the iframe") + style: str = Field("", description="CSS style to apply to the component") allowtransparency: bool = Field( False, description="Allow transparency of the iframe" ) diff --git a/zt_backend/models/components/image.py b/zt_backend/models/components/image.py index 6d84aecb..fb2ba9a0 100644 --- a/zt_backend/models/components/image.py +++ b/zt_backend/models/components/image.py @@ -10,6 +10,7 @@ class Image(ZTComponent): component: str = Field("v-img", description="Vue component name") src: str = Field(..., description="Source URL or Path of the image") alt: str = Field("", description="Alternative text for the image") + style: str = Field("", description="CSS style to apply to the component") width: Union[int, str] = Field("100%", description="Width of the image") height: Union[int, str] = Field("100%", description="Height of the image") diff --git a/zt_backend/models/components/matplotlib.py b/zt_backend/models/components/matplotlib.py index 567c2728..2b0241ee 100644 --- a/zt_backend/models/components/matplotlib.py +++ b/zt_backend/models/components/matplotlib.py @@ -12,12 +12,19 @@ class Matplotlib(ZTComponent): component: str = Field("v-img", description="Vue component name") src: str = Field(..., description="Source URL of the image of the graph") alt: str = Field("", description="Alternative text for the graph image") + style: str = Field("", description="CSS style to apply to the component") width: Union[int, str] = Field("100%", description="Width of the graph") height: Union[int, str] = Field("100%", description="Height of the graph") @classmethod def from_matplotlib( - cls, id: str, figure: plt.Figure, alt="", width=200, height=200 + cls, + id: str, + figure: plt.Figure, + alt="", + style="", + width=200, + height=200, ): """Create a Matplotlib component from a matplotlib figure""" plt.style.use("dark_background") @@ -26,10 +33,10 @@ def from_matplotlib( buffer.seek(0) base64_data = base64.b64encode(buffer.read()).decode() src = f"data:image/png;base64,{base64_data}" - return cls(id=id, src=src, alt=alt, width=width, height=height) + return cls(id=id, src=src, alt=alt, style=style, width=width, height=height) -def matplotlib(id: str, figure: plt.Figure, alt="", width=200, height=200): +def matplotlib(id: str, figure: plt.Figure, alt="", style="", width=200, height=200): """Create a Matplotlib component from a matplotlib figure""" plt.style.use("dark_background") buffer = BytesIO() @@ -37,4 +44,4 @@ def matplotlib(id: str, figure: plt.Figure, alt="", width=200, height=200): buffer.seek(0) base64_data = base64.b64encode(buffer.read()).decode() src = f"data:image/png;base64,{base64_data}" - return Matplotlib(id=id, src=src, alt=alt, width=width, height=height) + return Matplotlib(id=id, src=src, alt=alt, style=style, width=width, height=height) diff --git a/zt_backend/models/components/number_input.py b/zt_backend/models/components/number_input.py index 4ca0696c..fa96ee71 100644 --- a/zt_backend/models/components/number_input.py +++ b/zt_backend/models/components/number_input.py @@ -25,6 +25,7 @@ class NumberInput(ZTComponent): step: Optional[Union[int, float]] = Field( 1, description="The number to increment or decrement by" ) + style: Optional[str] = Field("", description="CSS style to apply to the component") triggerEvent: str = Field( None, description="Trigger event to send code to the backend" ) diff --git a/zt_backend/models/components/range_slider.py b/zt_backend/models/components/range_slider.py index 2b6755e3..cb555920 100644 --- a/zt_backend/models/components/range_slider.py +++ b/zt_backend/models/components/range_slider.py @@ -1,38 +1,54 @@ -from typing import List, Optional,Union +from typing import List, Optional, Union from pydantic import Field, field_validator, validator from zt_backend.models.components.zt_component import ZTComponent from zt_backend.models.components.validations import validate_color from zt_backend.models.state.user_state import UserContext + class RangeSlider(ZTComponent): """A slider component that allows a user to select a range of values""" + component: str = Field("v-range-slider", description="Vue component name") - value: List[Union[int,float]] = Field([0, 100], description="Current value range of the slider") - min: Union[int,float] = Field(0, description="Minimum value of the slider") - max: Union[int,float] = Field(100, description="Maximum value of the slider") - step: Union[int,float] = Field(1, gt=0, description="Step increment of the slider") - thumb_label: str = Field('always', description="Displays the thumb label") + value: List[Union[int, float]] = Field( + [0, 100], description="Current value range of the slider" + ) + min: Union[int, float] = Field(0, description="Minimum value of the slider") + max: Union[int, float] = Field(100, description="Maximum value of the slider") + step: Union[int, float] = Field(1, gt=0, description="Step increment of the slider") + thumb_label: str = Field("always", description="Displays the thumb label") thumb_size: int = Field(0, description="Size of the thumb") tick_labels: bool = Field(False, description="Displays the tick labels") ticks: list = Field([], description="Displays the ticks") - color: str = Field('primary', pre=True, description="Color of the range slider. Can be custom or standard Material color") - size: str = Field('large', description="Size of the slider") - label: Optional[str] = Field(None,description= 'A label for your slider') - rounded: bool = Field(True, description="Determines if the slider has rounded edges") - triggerEvent: str = Field('end',description="Trigger event for when to trigger a run") - - @field_validator('color') + color: str = Field( + "primary", + pre=True, + description="Color of the range slider. Can be custom or standard Material color", + ) + size: str = Field("large", description="Size of the slider") + label: Optional[str] = Field(None, description="A label for your slider") + rounded: bool = Field( + True, description="Determines if the slider has rounded edges" + ) + style: Optional[str] = Field("", description="CSS style to apply to the component") + triggerEvent: str = Field( + "end", description="Trigger event for when to trigger a run" + ) + + @field_validator("color") def validate_color(cls, color): return validate_color(color) - - @validator('value', always=True) #TODO: debug and replace with field validator + + @validator("value", always=True) # TODO: debug and replace with field validator def get_value_from_global_state(cls, value, values): - id = values['id'] # Get the id if it exists in the field values + id = values["id"] # Get the id if it exists in the field values execution_state = UserContext.get_state() try: - if execution_state and id and id in execution_state.component_values: # Check if id exists in global_state - return execution_state.component_values[id] # Return the value associated with id in global_state + if ( + execution_state and id and id in execution_state.component_values + ): # Check if id exists in global_state + return execution_state.component_values[ + id + ] # Return the value associated with id in global_state except Exception as e: e return value # If id doesn't exist in global_state, return the original value - diff --git a/zt_backend/models/components/rating.py b/zt_backend/models/components/rating.py index 33e54212..539bf2e2 100644 --- a/zt_backend/models/components/rating.py +++ b/zt_backend/models/components/rating.py @@ -42,6 +42,7 @@ class Rating(ZTComponent): None, description="Array of labels to display next to each item" ) ripple: bool = Field(False, description="Applies the v-ripple directive") + style: Optional[str] = Field("", description="CSS style to apply to the component") triggerEvent: str = Field( "update:modelValue", description="Trigger event for when to run the rating" ) diff --git a/zt_backend/models/components/selectbox.py b/zt_backend/models/components/selectbox.py index 86285d6d..965ecb4e 100644 --- a/zt_backend/models/components/selectbox.py +++ b/zt_backend/models/components/selectbox.py @@ -37,6 +37,7 @@ class SelectBox(ZTComponent): pre=True, description="Color of the range slider. Can be custom or standard Material color", ) + style: Optional[str] = Field("", description="CSS style to apply to the component") triggerEvent: str = Field( "update:modelValue", description="Trigger event for when to trigger a run" ) diff --git a/zt_backend/models/components/slider.py b/zt_backend/models/components/slider.py index 43bf1d54..c8841b9a 100644 --- a/zt_backend/models/components/slider.py +++ b/zt_backend/models/components/slider.py @@ -4,34 +4,49 @@ from typing import Optional, Union from zt_backend.models.state.user_state import UserContext + class Slider(ZTComponent): """A slider component that allows you to capture numeric input from a user""" + component: str = Field("v-slider", description="Vue component name") - value: Union[int,float] = Field(0, description="Current value of the slider") - min: Union[int,float] = Field(0, description="Minimum value of the slider") - max: Union[int,float] = Field(100, description="Maximum value of the slider") - step: Union[int,float] = Field(1, description="Step increment of the slider") - thumb_label: str = Field('always', description="Displays the thumb label") + value: Union[int, float] = Field(0, description="Current value of the slider") + min: Union[int, float] = Field(0, description="Minimum value of the slider") + max: Union[int, float] = Field(100, description="Maximum value of the slider") + step: Union[int, float] = Field(1, description="Step increment of the slider") + thumb_label: str = Field("always", description="Displays the thumb label") thumb_size: int = Field(0, description="Size of the thumb") - tick_labels: str = Field('always', description="When to display tick_labels") + tick_labels: str = Field("always", description="When to display tick_labels") ticks: list = Field([], description="Value of tick labels") - color: str = Field('primary', pre=True, description="Color of the range slider. Can be custom or standard Material color") - size: str = Field('large', description="Size of the slider") - label: Optional[str] = Field(None,description= 'A label for your slider') - rounded: bool = Field(True, description="Determines if the slider has rounded edges") - triggerEvent: str = Field('end',description="Trigger event for when to run the slider") - - @field_validator('color') + color: str = Field( + "primary", + pre=True, + description="Color of the range slider. Can be custom or standard Material color", + ) + size: str = Field("large", description="Size of the slider") + label: Optional[str] = Field(None, description="A label for your slider") + rounded: bool = Field( + True, description="Determines if the slider has rounded edges" + ) + style: Optional[str] = Field("", description="CSS style to apply to the component") + triggerEvent: str = Field( + "end", description="Trigger event for when to run the slider" + ) + + @field_validator("color") def validate_color(cls, color): return validate_color(color) - - @validator('value', always=True) #TODO: debug and replace with field validator + + @validator("value", always=True) # TODO: debug and replace with field validator def get_value_from_global_state(cls, value, values): - id = values['id'] # Get the id if it exists in the field values + id = values["id"] # Get the id if it exists in the field values execution_state = UserContext.get_state() try: - if execution_state and id and id in execution_state.component_values: # Check if id exists in global_state - return execution_state.component_values[id] # Return the value associated with id in global_state + if ( + execution_state and id and id in execution_state.component_values + ): # Check if id exists in global_state + return execution_state.component_values[ + id + ] # Return the value associated with id in global_state except Exception as e: e - return value # If id doesn't exist in global_state, return the original value \ No newline at end of file + return value # If id doesn't exist in global_state, return the original value diff --git a/zt_backend/models/components/text_area_input.py b/zt_backend/models/components/text_area_input.py index defbc684..2ae06664 100644 --- a/zt_backend/models/components/text_area_input.py +++ b/zt_backend/models/components/text_area_input.py @@ -20,6 +20,7 @@ class TextArea(ZTComponent): disabled: Optional[bool] = Field( False, description="If true, the input is disabled" ) + style: Optional[str] = Field("", description="CSS style to apply to the component") triggerEvent: str = Field( None, description="Trigger event to send code to the backend" ) diff --git a/zt_backend/models/components/text_input.py b/zt_backend/models/components/text_input.py index 86c7bc92..323ed0a0 100644 --- a/zt_backend/models/components/text_input.py +++ b/zt_backend/models/components/text_input.py @@ -20,6 +20,7 @@ class TextInput(ZTComponent): disabled: Optional[bool] = Field( False, description="If true, the input is disabled" ) + style: Optional[str] = Field("", description="CSS style to apply to the component") triggerEvent: str = Field( None, description="Trigger event to send code to the backend" ) From f1ea0e058060827dfb1af353b9b9f2b465cfc211 Mon Sep 17 00:00:00 2001 From: Jonathan Meyers Date: Mon, 9 Dec 2024 19:38:47 +0000 Subject: [PATCH 2/2] chore(main): release 0.5.1 (#385) --- CHANGELOG.md | 7 +++++++ setup.cfg | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b13e7a2..f6f8ace5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.5.1](https://github.com/Zero-True/zero-true/compare/v0.5.0...v0.5.1) (2024-12-09) + + +### Bug Fixes + +* Add style attribute to all relevant components ([#384](https://github.com/Zero-True/zero-true/issues/384)) ([68f42f7](https://github.com/Zero-True/zero-true/commit/68f42f7eb76ef58b9e1263e793b2490a58fd4f9e)) + ## [0.5.0](https://github.com/Zero-True/zero-true/compare/v0.4.9...v0.5.0) (2024-11-25) diff --git a/setup.cfg b/setup.cfg index 003a6ba0..f593d6e5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -8,7 +8,7 @@ license_files = LICENSE description = A collaborative notebook built for data scientists long_description = file: README.md long_description_content_type = text/markdown -version = 0.5.0 +version = 0.5.1 [options]