프로젝트 명(폴더) : demo_board
# | 파일 경로 | 설명 | 구분 |
1 | pcconfig.py | ||
2 | demo_board > demo_board.py | ||
3 | demo_board > demo_state.py | ||
4 | demo_board > demo_auth.py | ||
5 | demo_board > demo_servers.py | 다중 Select 컴포넌트 추가 및 Dummy 데이터 | 수정 |
6 | demo_board > demo_helpers.py |
서버 모니터링 demo_servers.py 에서 선택되는 Select 컴포넌트의 값에 따라서 여러 종류의 서버 유형의 결과를 조회하기위해서
Table 상단에 다중 Select 를 추가합니다.
수정전
수정후
Select 항목 선택후 "검색" 결과
수정된 내용
SeverState에서 사용할 함수들..
# Select 컴포넌트 2개에 표시될 데이터 List[Dict] Dummy 를 Dataframe으로 리턴
def get_select_data():
result_list = [
{'service_id': 'app_mng', 'parent_id': 'servers', 'service_nm': '인프라 서버 관리'},
{'service_id': 'app_web', 'parent_id': 'app_mng', 'service_nm': 'WEB 서버 관리'},
{'service_id': 'app_was', 'parent_id': 'app_mng', 'service_nm': 'WAS 서버 관리'},
{'service_id': 'app_rds', 'parent_id': 'app_mng', 'service_nm': 'DB 서버 관리'}
]
result_list = pd.DataFrame(result_list)
return result_list
# Dummy 를 Dataframe에서 상위 즉 parent_id가 동일한 항목들을 List로 리턴
def get_select_options(select_list, parent_id):
return select_list[select_list['parent_id']==parent_id]['service_nm'].values.tolist()
# Dummy 를 Dataframe에서 선택된 service_name 으로 해당 Dict의 service_id를 찾아서 리턴
def get_select_id(select_list, select1_id, option):
selected_parent = select_list[select_list['parent_id']==select1_id]
select_selected=selected_parent[selected_parent['service_nm']==option]
select_id=""
if len(select_selected) > 0:
select_id=select_selected['service_id'].values[0]
return select_id
class ServerState(State):
class ServerState(State):
"""The Substate of base state for the server page."""
print("──────────────────── [ ServerState(State) ] ────────────────────")
app_name: str = "Servers" #1 Navigation Bar에 표시될 Page 명
# (추가됨)
# select 컴포넌트에서 사용할 Dummy 데이타
select_list = get_select_data()
# 화면 로드시에 첫번째 Select 컴포넌트에 값을 세팅
select1_options: list[str] = get_select_options(select_list, "servers")
# 두번째 Select는 빈값으로 두고 첫번째 Select가 선택될때 이벤트를 받아서 항목을 추가
select2_options: list[str] = []
# 현재 선택된 Select 항목의 값들을 저장하기위한 vars
select1_id: str = ""
select2_id: str = ""
select1_value: str = ""
select2_value: str = ""
...(생략)
# (추가됨) Select 컴포넌트에서 on_change 이벤트가 발생할때 호출
def select_change(self, level, value):
# 선택항목이 select1 이면,
if(level == "select1"):
self.select1_id=""
self.select1_value=""
self.select2_id=""
self.select2_value=""
self.select2_options=[]
# 선택된 Option service_nm 값으로 해당 select_id를 찾아온다.
select_id = get_select_id(self.select_list, "servers", value)
self.select1_id=select_id
self.select1_value=value
# 앞서 찾은 select1의 id 값으로 select2 컴포넌트를위한 옵션 List를 조회/등록
self.select2_options=get_select_options(self.select_list, select_id)
elif(level == "select2"):
# Select2 가 선택됐을때는 선택된 service_nm에 대한 service_id 를 찾아 var에 저장
select_id = get_select_id(self.select_list, self.select1_id, value)
self.select2_id=select_id
self.select2_value=value
else:
return
# (추가됨) select_change에서 선택된 값들을 해서 "검색" 버튼 클릭시 데이터를 조회
def get_data_list(self):
pd_result_list: List[Dict] = get_data(self.select2_id)
self.table_columns = list(pd_result_list.columns)
self.table_data = pd_result_list.values.tolist()
다중 Select 컴포넌트 그리기
def search_select(ServerState):
"""The Multi Select combo."""
return pc.box(
pc.hstack(
pc.hstack(
pc.select(
ServerState.select1_options,
placeholder="Select an Option.",
on_change=lambda value: ServerState.select_change('select1', value),
#is_disabled=True,
border_style="solid",
border_width="1px",
border_color="#43464B",
value=ServerState.select1_value,
),
pc.select(
ServerState.select2_options,
placeholder="Select an Option.",
on_change=lambda value: ServerState.select_change('select2', value),
#is_disabled=True,
border_style="solid",
border_width="1px",
border_color="#43464B",
value=ServerState.select2_value,
),
pc.button(
"검색", #Search
bg="navy", #gray
color="white",
size="md",
width="150px",
on_click=ServerState.get_data_list,
),
border_width="0px",
),
border_width="0px",
),
#position="fixed",
#width="40%",
#top="105px",
z_index="500",
)
마지막으로 "/server" 함수에 search_select 추가
def servers():
return pc.box(
pc.vstack(
navbar(State, ServerState.app_name), #2 맨위 상단에 navbar를 추가
pc.cond(
State.logged_in,
pc.box(
#pc.heading("서버 모니터링", font_size="2em"),
#pc.heading("서버 모니터링"),
search_select(ServerState), # search_select 추가
render_table(ServerState),
#pc.divider(),
#render_datatable(ServerState),
),
width="100%",
border_width="0px",
),
pc.link(
pc.button("먼저 로그인 하세요"),
href="/login",
color="rgb(107,99,246)",
button=True,
)
),
padding_top="5.5em",
width="100%",
),
)
전체소스
import pynecone as pc
import pandas as pd
from typing import List, Dict
from .demo_state import State # Substate of Base State
from .demo_helpers import navbar
def get_select_data():
result_list = [
{'service_id': 'app_mng', 'parent_id': 'servers', 'service_nm': '인프라 서버 관리'},
{'service_id': 'app_web', 'parent_id': 'app_mng', 'service_nm': 'WEB 서버 관리'},
{'service_id': 'app_was', 'parent_id': 'app_mng', 'service_nm': 'WAS 서버 관리'},
{'service_id': 'app_rds', 'parent_id': 'app_mng', 'service_nm': 'DB 서버 관리'}
]
result_list = pd.DataFrame(result_list)
return result_list
def get_select_options(select_list, parent_id):
return select_list[select_list['parent_id']==parent_id]['service_nm'].values.tolist()
def get_select_id(select_list, select1_id, option):
selected_parent = select_list[select_list['parent_id']==select1_id]
select_selected=selected_parent[selected_parent['service_nm']==option]
select_id=""
if len(select_selected) > 0:
select_id=select_selected['service_id'].values[0]
return select_id
def get_data(server_type):
# 샘플 데이터 List[Dict]
if server_type == "" or server_type == None:
result_list = [{'Result': 'No data found (검색 조건을 선택한 후 조회 버튼을 클릭하세요)'}]
else:
result_list = [
{"Server Type": server_type, "Server Name": "alpha", "Total Disk": "10G", "Used Disk": "5G", "Available Disk": "5G", "HTTPS Status": "running", "Last Access": "17/Feb/2023:17:13:51"},
{"Server Type": server_type, "Server Name": "brovo", "Total Disk": "10G", "Used Disk": "5G", "Available Disk": "5G", "HTTPS Status": "running", "Last Access": "17/Feb/2023:17:13:51"},
{"Server Type": server_type, "Server Name": "charlie", "Total Disk": "10G", "Used Disk": "5G", "Available Disk": "5G", "HTTPS Status": "running", "Last Access": "17/Feb/2023:17:13:51"},
{"Server Type": server_type, "Server Name": "delta", "Total Disk": "10G", "Used Disk": "5G", "Available Disk": "5G", "HTTPS Status": "running", "Last Access": "17/Feb/2023:17:13:51"},
{"Server Type": server_type, "Server Name": "echo", "Total Disk": "10G", "Used Disk": "5G", "Available Disk": "5G", "HTTPS Status": "running", "Last Access": "17/Feb/2023:17:13:51"},
]
pd_result_list = pd.DataFrame(result_list)
pd_result_list=pd_result_list.fillna('') # NaN값을 0 or ''로 치환한다.
pd_result_list=pd_result_list.astype(str) # 전체 Field를 str로 변환한다.
return pd_result_list
class ServerState(State):
"""The Substate of base state for the server page."""
print("──────────────────── [ ServerState(State) ] ────────────────────")
app_name: str = "Servers" #1 Navigation Bar에 표시될 Page 명
select_list = get_select_data()
select1_options: list[str] = get_select_options(select_list, "servers")
select2_options: list[str] = []
select1_id: str = ""
select2_id: str = ""
select1_value: str = ""
select2_value: str = ""
pd_result_list: List[Dict] = get_data("")
#print(pd_result_list)
# table_columns : Dict에서 Columns 정보를 가져와서 Table의 thead를 구성
# table_data : Dataframe에서 value만 List로 만들어서 Table의 tbody를 구성
# table_name : Table의 table_caption
table_columns = list(pd_result_list.columns)
table_data: List[List[str]] = pd_result_list.values.tolist()
table_name: str = "WEB 서버 상태 확인"
box_align: str = ""
def select_change(self, level, value):
if(level == "select1"):
self.select1_id=""
self.select1_value=""
self.select2_id=""
self.select2_value=""
self.select2_options=[]
select_id = get_select_id(self.select_list, "servers", value)
self.select1_id=select_id
self.select1_value=value
self.select2_options=get_select_options(self.select_list, select_id)
elif(level == "select2"):
select_id = get_select_id(self.select_list, self.select1_id, value)
self.select2_id=select_id
self.select2_value=value
else:
return
def get_data_list(self):
pd_result_list: List[Dict] = get_data(self.select2_id)
self.table_columns = list(pd_result_list.columns)
self.table_data = pd_result_list.values.tolist()
def servers():
return pc.box(
pc.vstack(
navbar(State, ServerState.app_name), #2 맨위 상단에 navbar를 추가
pc.cond(
State.logged_in,
pc.box(
pc.vstack(
search_select(ServerState),
render_table(ServerState),
#pc.divider(),
#render_datatable(ServerState),
),
width="100%",
border_width="0px",
),
pc.link(
pc.button("먼저 로그인 하세요"),
href="/login",
color="rgb(107,99,246)",
button=True,
)
),
padding_top="5.5em",
width="100%",
),
)
def search_select(ServerState):
"""The Multi Select combo."""
return pc.box(
pc.hstack(
pc.hstack(
pc.select(
ServerState.select1_options,
placeholder="Select an Option.",
on_change=lambda value: ServerState.select_change('select1', value),
#is_disabled=True,
border_style="solid",
border_width="1px",
border_color="#43464B",
value=ServerState.select1_value,
),
pc.select(
ServerState.select2_options,
placeholder="Select an Option.",
on_change=lambda value: ServerState.select_change('select2', value),
#is_disabled=True,
border_style="solid",
border_width="1px",
border_color="#43464B",
value=ServerState.select2_value,
),
pc.button(
"검색", #Search
bg="navy", #gray
color="white",
size="md",
width="150px",
on_click=ServerState.get_data_list,
),
border_width="0px",
),
border_width="0px",
),
#position="fixed",
#width="40%",
#top="105px",
z_index="500",
)
def render_tbody_tr(tr_data, index):
return pc.tr(
pc.td(index + 1),
pc.foreach(tr_data, lambda data: pc.td(data)),
)
def render_table(ServerState):
return pc.box(
pc.vstack(
pc.table(
pc.table_caption(ServerState.table_name),
pc.thead(
pc.tr(
pc.td("#"),
pc.foreach(ServerState.table_columns, lambda data: pc.td(data)),
),
bg="navy",
color="white",
),
pc.tbody(
pc.foreach(ServerState.table_data, lambda data, i: render_tbody_tr(data, i)),
),
),
border_width="1px",
overflow="auto",
),
padding_top="1em",
width="98%",
)
def render_datatable(ServerState):
return pc.box(
pc.vstack(
pc.data_table(
data=ServerState.pd_result_list,
pagination=True,
search=True,
sort=False, #True, False
resizable=True,
border_color="#43464B",
),
width="100%",
#align_items="start",
#align_items="left",
align_items=ServerState.box_align,
#padding_x="15%",
overflow="auto",
#overflow_x="scroll",
#overflow_y="scroll",
),
border_width="0px",
border_color="#43464B",
width="98%",
)
'python > pynecone' 카테고리의 다른 글
9. pynecon Demo 조회시 CircularProgress 추가 (0) | 2023.03.17 |
---|---|
8. pynecon Demo 검색 on_click시 다중 이벤트로 Progress 보여주기 (0) | 2023.02.28 |
6.pynecone Demo List[Dict] typing table, DataTable 추가 (0) | 2023.02.18 |
5.pynecone Demo Navigation에 Menu 추가 (0) | 2023.02.18 |
3.pynecone Demo 로그인/로그아웃 구현 (0) | 2023.02.18 |