-
Notifications
You must be signed in to change notification settings - Fork 10
/
streamlit_app.py
172 lines (153 loc) · 5.87 KB
/
streamlit_app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import datetime
import random
import altair as alt
import numpy as np
import pandas as pd
import streamlit as st
# Show app title and description.
st.set_page_config(page_title="Support ticket workflow", page_icon="🎫")
st.title("🎫 Support ticket workflow")
st.write(
"""
This app shows how you can build an internal tool in Streamlit. Here, we are
implementing a support ticket workflow. The user can create a ticket, edit
existing tickets, and view some statistics.
"""
)
# Create a random Pandas dataframe with existing tickets.
if "df" not in st.session_state:
# Set seed for reproducibility.
np.random.seed(42)
# Make up some fake issue descriptions.
issue_descriptions = [
"Network connectivity issues in the office",
"Software application crashing on startup",
"Printer not responding to print commands",
"Email server downtime",
"Data backup failure",
"Login authentication problems",
"Website performance degradation",
"Security vulnerability identified",
"Hardware malfunction in the server room",
"Employee unable to access shared files",
"Database connection failure",
"Mobile application not syncing data",
"VoIP phone system issues",
"VPN connection problems for remote employees",
"System updates causing compatibility issues",
"File server running out of storage space",
"Intrusion detection system alerts",
"Inventory management system errors",
"Customer data not loading in CRM",
"Collaboration tool not sending notifications",
]
# Generate the dataframe with 100 rows/tickets.
data = {
"ID": [f"TICKET-{i}" for i in range(1100, 1000, -1)],
"Issue": np.random.choice(issue_descriptions, size=100),
"Status": np.random.choice(["Open", "In Progress", "Closed"], size=100),
"Priority": np.random.choice(["High", "Medium", "Low"], size=100),
"Date Submitted": [
datetime.date(2023, 6, 1) + datetime.timedelta(days=random.randint(0, 182))
for _ in range(100)
],
}
df = pd.DataFrame(data)
# Save the dataframe in session state (a dictionary-like object that persists across
# page runs). This ensures our data is persisted when the app updates.
st.session_state.df = df
# Show a section to add a new ticket.
st.header("Add a ticket")
# We're adding tickets via an `st.form` and some input widgets. If widgets are used
# in a form, the app will only rerun once the submit button is pressed.
with st.form("add_ticket_form"):
issue = st.text_area("Describe the issue")
priority = st.selectbox("Priority", ["High", "Medium", "Low"])
submitted = st.form_submit_button("Submit")
if submitted:
# Make a dataframe for the new ticket and append it to the dataframe in session
# state.
recent_ticket_number = int(max(st.session_state.df.ID).split("-")[1])
today = datetime.datetime.now().strftime("%Y-%m-%d")
df_new = pd.DataFrame(
[
{
"ID": f"TICKET-{recent_ticket_number+1}",
"Issue": issue,
"Status": "Open",
"Priority": priority,
"Date Submitted": today,
}
]
)
# Show a little success message.
st.write("Ticket submitted! Here are the ticket details:")
st.dataframe(df_new, use_container_width=True, hide_index=True)
st.session_state.df = pd.concat([df_new, st.session_state.df], axis=0)
# Show section to view and edit existing tickets in a table.
st.header("Existing tickets")
st.write(f"Number of tickets: `{len(st.session_state.df)}`")
st.info(
"You can edit the tickets by double clicking on a cell. Note how the plots below "
"update automatically! You can also sort the table by clicking on the column headers.",
icon="✍️",
)
# Show the tickets dataframe with `st.data_editor`. This lets the user edit the table
# cells. The edited data is returned as a new dataframe.
edited_df = st.data_editor(
st.session_state.df,
use_container_width=True,
hide_index=True,
column_config={
"Status": st.column_config.SelectboxColumn(
"Status",
help="Ticket status",
options=["Open", "In Progress", "Closed"],
required=True,
),
"Priority": st.column_config.SelectboxColumn(
"Priority",
help="Priority",
options=["High", "Medium", "Low"],
required=True,
),
},
# Disable editing the ID and Date Submitted columns.
disabled=["ID", "Date Submitted"],
)
# Show some metrics and charts about the ticket.
st.header("Statistics")
# Show metrics side by side using `st.columns` and `st.metric`.
col1, col2, col3 = st.columns(3)
num_open_tickets = len(edited_df[edited_df.Status == "Open"])
col1.metric(label="Number of open tickets", value=num_open_tickets, delta=10)
col2.metric(label="First response time (hours)", value=5.2, delta=-1.5)
col3.metric(label="Average resolution time (hours)", value=16, delta=2)
# Show two Altair charts using `st.altair_chart`.
st.write("")
st.write("##### Ticket status per month")
status_plot = (
alt.Chart(edited_df)
.mark_bar()
.encode(
x="month(Date Submitted):O",
y="count():Q",
xOffset="Status:N",
color="Status:N",
)
.configure_legend(
orient="bottom", titleFontSize=14, labelFontSize=14, titlePadding=5
)
)
st.altair_chart(status_plot, use_container_width=True, theme="streamlit")
st.write("##### Current ticket priorities")
priority_plot = (
alt.Chart(edited_df)
.mark_arc()
.encode(theta="count():Q", color="Priority:N")
.properties(height=300)
.configure_legend(
orient="bottom", titleFontSize=14, labelFontSize=14, titlePadding=5
)
)
st.altair_chart(priority_plot, use_container_width=True, theme="streamlit")