프로젝트 명(폴더) : 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%",
    )

+ Recent posts