Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ jobs:
ai_image_gen)
echo "EXTRA_ARGS=--env REPLICATE_API_TOKEN=${{ secrets.REPLICATE_API_TOKEN }}" >> $GITHUB_ENV
;;
business_analytics_dashboard)
echo "EXTRA_ARGS=" >> $GITHUB_ENV
;;
manufacturing_dashboard)
echo "EXTRA_ARGS=" >> $GITHUB_ENV
;;
customer_data_app)
cat .deploy/temporary_db.py >> ${{ matrix.folder }}/customer_data/customer_data.py
echo "EXTRA_ARGS=--vmtype ${{ vars.CUSTOMER_DATA_VM_TYPE }}" >> $GITHUB_ENV
Expand Down
8 changes: 8 additions & 0 deletions manufacturing_dashboard/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.web
*.db
.states
assets/external/
*.py[cod]
__pycache__/
.DS_Store
.idea/
Binary file added manufacturing_dashboard/assets/favicon.ico
Binary file not shown.
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import reflex as rx

from manufacturing_dashboard.states.dashboard_state import DashboardState


def dashboard_header() -> rx.Component:
"""Renders the header section of the dashboard."""
return rx.el.div(
rx.el.div(
rx.el.h1(
"CONTROL CHARTS DASHBOARD",
class_name="text-xs font-semibold text-slate-400 tracking-wider uppercase mr-4",
),
rx.el.button(
rx.cond(
DashboardState.is_running,
"Running...",
"Start Process",
),
on_click=DashboardState.start_process,
disabled=DashboardState.is_running,
class_name=rx.cond(
DashboardState.is_running,
"px-4 py-1.5 text-sm font-medium text-slate-300 bg-slate-700 rounded-md opacity-50 cursor-not-allowed",
"px-4 py-1.5 text-sm font-medium text-white bg-cyan-600 rounded-md hover:bg-cyan-700 transition-colors duration-150",
),
),
class_name="flex flex-1 justify-between items-center border-b-2 border-cyan-600 pb-2",
),
class_name="flex justify-between items-center mb-8",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import reflex as rx

from manufacturing_dashboard.states.dashboard_state import DashboardState


def distribution_chart() -> rx.Component:
"""Renders the vertical bar chart for distribution data."""
return rx.el.div(
rx.el.h2(
"Diameter Distribution",
class_name="text-xl font-semibold text-slate-200 mb-2 text-center px-4 pt-4",
),
rx.recharts.bar_chart(
rx.recharts.cartesian_grid(
stroke_dasharray="3 3",
stroke="#475569",
horizontal=True,
vertical=False,
),
rx.recharts.x_axis(data_key="name", type_="category", hide=True),
rx.recharts.y_axis(
type_="number",
allow_decimals=False,
axis_line=False,
tick_line=False,
width=30,
stroke="#94a3b8",
font_size="10px",
),
rx.recharts.bar(
data_key="value",
fill="#fbbf24",
radius=[4, 4, 0, 0],
is_animation_active=False,
label_list={
"position": "right",
"fill": "#e2e8f0",
"font_size": "10px",
"offset": 5,
},
),
data=DashboardState.distribution_data,
layout="vertical",
bar_category_gap="25%",
margin={
"top": 10,
"right": 30,
"left": 5,
"bottom": 0,
},
width="100%",
height=320,
),
class_name="bg-slate-800 rounded-lg shadow-lg border border-slate-700 h-[380px] flex flex-col w-full",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
from typing import Dict, List

import reflex as rx

from manufacturing_dashboard.states.dashboard_state import (
DashboardState,
)


def sparkline_chart(
data: rx.Var[List[Dict[str, int]]],
) -> rx.Component:
"""Renders a small sparkline chart for the metrics table."""
return rx.recharts.line_chart(
rx.recharts.line(
data_key="uv",
stroke="#fbbf24",
stroke_width=2,
dot=False,
is_animation_active=False,
),
data=data,
width=120,
height=40,
margin={
"top": 5,
"right": 0,
"left": 0,
"bottom": 5,
},
)


def ooc_progress_bar(
percentage: rx.Var[float],
) -> rx.Component:
"""Renders a segmented progress bar for OOC percentage.
Teal: 0-3%, Amber: 3-7%, Red: 7-10%
"""
teal_width = rx.cond(percentage <= 3, percentage * 100 / 3, 100).to_string() + "%"
yellow_width = (
rx.cond(
percentage > 3,
rx.cond(
percentage <= 7,
(percentage - 3) * 100 / 4,
100,
),
0,
).to_string()
+ "%"
)
red_width = (
rx.cond(
percentage > 7,
rx.cond(
percentage <= 10,
(percentage - 7) * 100 / 3,
100,
),
0,
).to_string()
+ "%"
)
return rx.el.div(
rx.el.div(
rx.el.div(
style={"width": teal_width},
class_name="h-full bg-teal-500 rounded-l",
),
class_name="w-1/3 h-full",
),
rx.el.div(
rx.el.div(
style={"width": yellow_width},
class_name="h-full bg-amber-400",
),
class_name="w-1/3 h-full",
),
rx.el.div(
rx.el.div(
style={"width": red_width},
class_name="h-full bg-red-500 rounded-r",
),
class_name="w-1/3 h-full",
),
class_name="w-24 h-3 bg-slate-600 rounded flex overflow-hidden shadow-inner",
)


def pass_fail_indicator(
status: rx.Var[bool],
) -> rx.Component:
"""Renders a small colored dot indicating pass (amber) or fail (red)."""
return rx.el.div(
class_name=rx.cond(
status,
"w-3 h-3 rounded-full bg-amber-400 shadow-md",
"w-3 h-3 rounded-full bg-red-500 shadow-md",
)
)


def metrics_summary() -> rx.Component:
"""Renders the main table for process control metrics."""
headers = [
"Parameter",
"Count",
"Trend",
"OOC %",
"% OOC Bar",
"Status",
]
return rx.el.div(
rx.el.h2(
"Process Control Metrics Summary",
class_name="text-xl font-semibold text-slate-200 mb-4",
),
rx.el.div(
rx.el.table(
rx.el.thead(
rx.el.tr(
rx.foreach(
headers,
lambda header: rx.el.th(
header,
class_name="px-5 py-3 text-left text-xs font-medium text-slate-400 uppercase tracking-wider border-b border-slate-700 bg-slate-800",
),
)
)
),
rx.el.tbody(
rx.foreach(
DashboardState.process_metrics,
lambda metric: rx.el.tr(
rx.el.td(
metric["parameter"],
class_name="px-5 py-4 whitespace-nowrap text-sm text-slate-300 border-b border-slate-700 font-medium",
),
rx.el.td(
metric["count"],
class_name="px-5 py-4 whitespace-nowrap text-sm text-slate-300 border-b border-slate-700",
),
rx.el.td(
sparkline_chart(metric["sparkline_data"]),
class_name="px-5 py-2 border-b border-slate-700",
),
rx.el.td(
metric["ooc_percent"].to_string() + "%",
class_name="px-5 py-4 whitespace-nowrap text-sm text-slate-300 border-b border-slate-700 font-mono",
),
rx.el.td(
ooc_progress_bar(metric["ooc_percent"]),
class_name="px-5 py-4 border-b border-slate-700",
),
rx.el.td(
pass_fail_indicator(metric["pass_fail"]),
class_name="px-5 py-4 border-b border-slate-700",
),
class_name="hover:bg-slate-700/50 transition-colors duration-150",
),
)
),
class_name="min-w-full",
),
class_name="overflow-x-auto rounded-lg shadow-md border border-slate-700",
),
class_name="bg-slate-800 p-6 rounded-lg shadow-lg border border-slate-700 w-full mb-6",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import reflex as rx

from manufacturing_dashboard.states.dashboard_state import DashboardState


def ooc_pie_chart() -> rx.Component:
"""Renders the Pie chart showing % OOC per Parameter."""
return rx.el.div(
rx.el.h2(
"% OOC per Parameter",
class_name="text-xl font-semibold text-slate-200 mb-4 text-center",
),
rx.recharts.pie_chart(
rx.recharts.pie(
rx.foreach(
DashboardState.pie_data,
lambda item, index: rx.recharts.cell(fill=item["fill"]),
),
data=DashboardState.pie_data,
data_key="value",
name_key="name",
cx="50%",
cy="50%",
outer_radius="80%",
inner_radius="40%",
padding_angle=2,
label_line=False,
label=False,
is_animation_active=False,
),
rx.recharts.legend(
layout="vertical",
vertical_align="middle",
align="right",
icon_size=10,
icon_type="square",
wrapper_style={
"fontSize": "12px",
"color": "#94a3b8",
},
),
margin={
"top": 5,
"right": 5,
"left": 5,
"bottom": 5,
},
height=320,
width="100%",
),
class_name="bg-slate-800 p-6 rounded-lg shadow-lg border border-slate-700 h-[380px] flex flex-col justify-between w-full",
)
Loading