Skip to content

Commit c59968c

Browse files
authored
Merge branch 'main' into ahmad/stock-market-dashboard
2 parents 16e7c2b + 8c4462e commit c59968c

File tree

19 files changed

+921
-1
lines changed

19 files changed

+921
-1
lines changed

.github/workflows/deploy.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ jobs:
4141
business_analytics_dashboard)
4242
echo "EXTRA_ARGS=" >> $GITHUB_ENV
4343
;;
44+
manufacturing_dashboard)
45+
echo "EXTRA_ARGS=" >> $GITHUB_ENV
46+
;;
4447
customer_data_app)
4548
cat .deploy/temporary_db.py >> ${{ matrix.folder }}/customer_data/customer_data.py
4649
echo "EXTRA_ARGS=--vmtype ${{ vars.CUSTOMER_DATA_VM_TYPE }}" >> $GITHUB_ENV

manufacturing_dashboard/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.web
2+
*.db
3+
.states
4+
assets/external/
5+
*.py[cod]
6+
__pycache__/
7+
.DS_Store
8+
.idea/
4.19 KB
Binary file not shown.

manufacturing_dashboard/blocks/__init__.py

Whitespace-only changes.

manufacturing_dashboard/manufacturing_dashboard/__init__.py

Whitespace-only changes.

manufacturing_dashboard/manufacturing_dashboard/components/__init__.py

Whitespace-only changes.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import reflex as rx
2+
3+
from manufacturing_dashboard.states.dashboard_state import DashboardState
4+
5+
6+
def dashboard_header() -> rx.Component:
7+
"""Renders the header section of the dashboard."""
8+
return rx.el.div(
9+
rx.el.div(
10+
rx.el.h1(
11+
"CONTROL CHARTS DASHBOARD",
12+
class_name="text-xs font-semibold text-slate-400 tracking-wider uppercase mr-4",
13+
),
14+
rx.el.button(
15+
rx.cond(
16+
DashboardState.is_running,
17+
"Running...",
18+
"Start Process",
19+
),
20+
on_click=DashboardState.start_process,
21+
disabled=DashboardState.is_running,
22+
class_name=rx.cond(
23+
DashboardState.is_running,
24+
"px-4 py-1.5 text-sm font-medium text-slate-300 bg-slate-700 rounded-md opacity-50 cursor-not-allowed",
25+
"px-4 py-1.5 text-sm font-medium text-white bg-cyan-600 rounded-md hover:bg-cyan-700 transition-colors duration-150",
26+
),
27+
),
28+
class_name="flex flex-1 justify-between items-center border-b-2 border-cyan-600 pb-2",
29+
),
30+
class_name="flex justify-between items-center mb-8",
31+
)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import reflex as rx
2+
3+
from manufacturing_dashboard.states.dashboard_state import DashboardState
4+
5+
6+
def distribution_chart() -> rx.Component:
7+
"""Renders the vertical bar chart for distribution data."""
8+
return rx.el.div(
9+
rx.el.h2(
10+
"Diameter Distribution",
11+
class_name="text-xl font-semibold text-slate-200 mb-2 text-center px-4 pt-4",
12+
),
13+
rx.recharts.bar_chart(
14+
rx.recharts.cartesian_grid(
15+
stroke_dasharray="3 3",
16+
stroke="#475569",
17+
horizontal=True,
18+
vertical=False,
19+
),
20+
rx.recharts.x_axis(data_key="name", type_="category", hide=True),
21+
rx.recharts.y_axis(
22+
type_="number",
23+
allow_decimals=False,
24+
axis_line=False,
25+
tick_line=False,
26+
width=30,
27+
stroke="#94a3b8",
28+
font_size="10px",
29+
),
30+
rx.recharts.bar(
31+
data_key="value",
32+
fill="#fbbf24",
33+
radius=[4, 4, 0, 0],
34+
is_animation_active=False,
35+
label_list={
36+
"position": "right",
37+
"fill": "#e2e8f0",
38+
"font_size": "10px",
39+
"offset": 5,
40+
},
41+
),
42+
data=DashboardState.distribution_data,
43+
layout="vertical",
44+
bar_category_gap="25%",
45+
margin={
46+
"top": 10,
47+
"right": 30,
48+
"left": 5,
49+
"bottom": 0,
50+
},
51+
width="100%",
52+
height=320,
53+
),
54+
class_name="bg-slate-800 rounded-lg shadow-lg border border-slate-700 h-[380px] flex flex-col w-full",
55+
)
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
from typing import Dict, List
2+
3+
import reflex as rx
4+
5+
from manufacturing_dashboard.states.dashboard_state import (
6+
DashboardState,
7+
)
8+
9+
10+
def sparkline_chart(
11+
data: rx.Var[List[Dict[str, int]]],
12+
) -> rx.Component:
13+
"""Renders a small sparkline chart for the metrics table."""
14+
return rx.recharts.line_chart(
15+
rx.recharts.line(
16+
data_key="uv",
17+
stroke="#fbbf24",
18+
stroke_width=2,
19+
dot=False,
20+
is_animation_active=False,
21+
),
22+
data=data,
23+
width=120,
24+
height=40,
25+
margin={
26+
"top": 5,
27+
"right": 0,
28+
"left": 0,
29+
"bottom": 5,
30+
},
31+
)
32+
33+
34+
def ooc_progress_bar(
35+
percentage: rx.Var[float],
36+
) -> rx.Component:
37+
"""Renders a segmented progress bar for OOC percentage.
38+
Teal: 0-3%, Amber: 3-7%, Red: 7-10%
39+
"""
40+
teal_width = rx.cond(percentage <= 3, percentage * 100 / 3, 100).to_string() + "%"
41+
yellow_width = (
42+
rx.cond(
43+
percentage > 3,
44+
rx.cond(
45+
percentage <= 7,
46+
(percentage - 3) * 100 / 4,
47+
100,
48+
),
49+
0,
50+
).to_string()
51+
+ "%"
52+
)
53+
red_width = (
54+
rx.cond(
55+
percentage > 7,
56+
rx.cond(
57+
percentage <= 10,
58+
(percentage - 7) * 100 / 3,
59+
100,
60+
),
61+
0,
62+
).to_string()
63+
+ "%"
64+
)
65+
return rx.el.div(
66+
rx.el.div(
67+
rx.el.div(
68+
style={"width": teal_width},
69+
class_name="h-full bg-teal-500 rounded-l",
70+
),
71+
class_name="w-1/3 h-full",
72+
),
73+
rx.el.div(
74+
rx.el.div(
75+
style={"width": yellow_width},
76+
class_name="h-full bg-amber-400",
77+
),
78+
class_name="w-1/3 h-full",
79+
),
80+
rx.el.div(
81+
rx.el.div(
82+
style={"width": red_width},
83+
class_name="h-full bg-red-500 rounded-r",
84+
),
85+
class_name="w-1/3 h-full",
86+
),
87+
class_name="w-24 h-3 bg-slate-600 rounded flex overflow-hidden shadow-inner",
88+
)
89+
90+
91+
def pass_fail_indicator(
92+
status: rx.Var[bool],
93+
) -> rx.Component:
94+
"""Renders a small colored dot indicating pass (amber) or fail (red)."""
95+
return rx.el.div(
96+
class_name=rx.cond(
97+
status,
98+
"w-3 h-3 rounded-full bg-amber-400 shadow-md",
99+
"w-3 h-3 rounded-full bg-red-500 shadow-md",
100+
)
101+
)
102+
103+
104+
def metrics_summary() -> rx.Component:
105+
"""Renders the main table for process control metrics."""
106+
headers = [
107+
"Parameter",
108+
"Count",
109+
"Trend",
110+
"OOC %",
111+
"% OOC Bar",
112+
"Status",
113+
]
114+
return rx.el.div(
115+
rx.el.h2(
116+
"Process Control Metrics Summary",
117+
class_name="text-xl font-semibold text-slate-200 mb-4",
118+
),
119+
rx.el.div(
120+
rx.el.table(
121+
rx.el.thead(
122+
rx.el.tr(
123+
rx.foreach(
124+
headers,
125+
lambda header: rx.el.th(
126+
header,
127+
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",
128+
),
129+
)
130+
)
131+
),
132+
rx.el.tbody(
133+
rx.foreach(
134+
DashboardState.process_metrics,
135+
lambda metric: rx.el.tr(
136+
rx.el.td(
137+
metric["parameter"],
138+
class_name="px-5 py-4 whitespace-nowrap text-sm text-slate-300 border-b border-slate-700 font-medium",
139+
),
140+
rx.el.td(
141+
metric["count"],
142+
class_name="px-5 py-4 whitespace-nowrap text-sm text-slate-300 border-b border-slate-700",
143+
),
144+
rx.el.td(
145+
sparkline_chart(metric["sparkline_data"]),
146+
class_name="px-5 py-2 border-b border-slate-700",
147+
),
148+
rx.el.td(
149+
metric["ooc_percent"].to_string() + "%",
150+
class_name="px-5 py-4 whitespace-nowrap text-sm text-slate-300 border-b border-slate-700 font-mono",
151+
),
152+
rx.el.td(
153+
ooc_progress_bar(metric["ooc_percent"]),
154+
class_name="px-5 py-4 border-b border-slate-700",
155+
),
156+
rx.el.td(
157+
pass_fail_indicator(metric["pass_fail"]),
158+
class_name="px-5 py-4 border-b border-slate-700",
159+
),
160+
class_name="hover:bg-slate-700/50 transition-colors duration-150",
161+
),
162+
)
163+
),
164+
class_name="min-w-full",
165+
),
166+
class_name="overflow-x-auto rounded-lg shadow-md border border-slate-700",
167+
),
168+
class_name="bg-slate-800 p-6 rounded-lg shadow-lg border border-slate-700 w-full mb-6",
169+
)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import reflex as rx
2+
3+
from manufacturing_dashboard.states.dashboard_state import DashboardState
4+
5+
6+
def ooc_pie_chart() -> rx.Component:
7+
"""Renders the Pie chart showing % OOC per Parameter."""
8+
return rx.el.div(
9+
rx.el.h2(
10+
"% OOC per Parameter",
11+
class_name="text-xl font-semibold text-slate-200 mb-4 text-center",
12+
),
13+
rx.recharts.pie_chart(
14+
rx.recharts.pie(
15+
rx.foreach(
16+
DashboardState.pie_data,
17+
lambda item, index: rx.recharts.cell(fill=item["fill"]),
18+
),
19+
data=DashboardState.pie_data,
20+
data_key="value",
21+
name_key="name",
22+
cx="50%",
23+
cy="50%",
24+
outer_radius="80%",
25+
inner_radius="40%",
26+
padding_angle=2,
27+
label_line=False,
28+
label=False,
29+
is_animation_active=False,
30+
),
31+
rx.recharts.legend(
32+
layout="vertical",
33+
vertical_align="middle",
34+
align="right",
35+
icon_size=10,
36+
icon_type="square",
37+
wrapper_style={
38+
"fontSize": "12px",
39+
"color": "#94a3b8",
40+
},
41+
),
42+
margin={
43+
"top": 5,
44+
"right": 5,
45+
"left": 5,
46+
"bottom": 5,
47+
},
48+
height=320,
49+
width="100%",
50+
),
51+
class_name="bg-slate-800 p-6 rounded-lg shadow-lg border border-slate-700 h-[380px] flex flex-col justify-between w-full",
52+
)

0 commit comments

Comments
 (0)