streamlit-bridge icon indicating copy to clipboard operation
streamlit-bridge copied to clipboard

Không hoạt động trong streamlit multipages

Open ayclqt opened this issue 11 months ago • 1 comments

Khi mình dùng st.html thì html_content vẫn hiện bình thường, nhưng khi dùng html từ st_bridge thì nó lại không hiện Code multipages:

  • users.py:
from datetime import datetime
from urllib.parse import urljoin
import streamlit as st
import requests
from src.config import api_url, api_path, config
from src.credentials import cookies
from src.crypt import decrypt
from st_bridge import bridge, html

# Nếu đã login thì hiện nội dung
st.title("Users Management")

headers = {
    "Authorization": f"Bearer {decrypt(cookies.get('token'))}"
}

@st.dialog("Thông tin người dùng")
def usrn(data):
    st.write(data)


def add_user(data):
    res=requests.post(f"{urljoin(api_url, api_path+config.get('api').get('users'))}", json=data, headers=headers)
    if res.status_code == 200:
        st.success("User added successfully")
        return True
    else:
        st.error("Error adding user")
        res.raise_for_status()  # Raise exception for bad status codes

@st.dialog("Add User")
def add_user_form():
    with st.form("add_user"):
        chatid=st.text_input("Chat ID")
        user=st.text_input("Username")
        balance=st.text_input("Balance")
        status=st.checkbox("Status")
        st.form_submit_button("Add User", on_click=add_user, args=[{"chatId": chatid, "username": user, "balance": balance, "status": 0 if not status else 1}])

try:
    res = requests.get(
        f"{urljoin(api_url, api_path+config.get('api').get('users'))}",
        headers=headers
    )
    res.raise_for_status()  # Raise exception for bad status codes
    # Tạo HTML component
    html_content = """
        <style>
            .container {
                font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            }
            .user-list {
                max-width: 800px;
                margin: 0 auto;
            }
            .user-item {
                display: flex;
                align-items: center;
                padding: 15px;
                margin: 8px 0;
                border: 1px solid #ddd;
                border-radius: 8px;
                cursor: pointer;
                transition: all 0.3s;
                background-color: white;
            }
            .user-item:hover {
                background-color: #f8f9fa;
                transform: translateX(5px);
                box-shadow: 0 2px 5px rgba(0,0,0,0.1);
            }
            .avatar {
                width: 45px;
                height: 45px;
                border-radius: 50%;
                display: flex;
                align-items: center;
                justify-content: center;
                color: white;
                font-weight: bold;
                margin-right: 15px;
                background-color: #0066cc;
            }
            .user-info {
                flex-grow: 1;
            }
            .status-badge {
                padding: 4px 8px;
                border-radius: 12px;
                color: white;
                font-size: 0.8em;
                margin-left: 10px;
            }
            .meta-info {
                color: #666;
                font-size: 0.9em;
                margin-top: 4px;
            }
            .active {
                background-color: #28a745;
            }
            .inactive {
                background-color: #dc3545;
            }
        </style>

        <div class="container">
            <div class="user-list">
        """

    # Thêm user items vào HTML
    for user in res.json().get("content"):
        status_class = "active" if user['status'] == 1 else "inactive"
        status_text = "Active" if user['status'] == 1 else "Inactive"

        html_content += f"""
                <div class="user-item" onclick="stBridges.send('click-id', {user['chatId']})">
                    <div class="avatar">
                        {user['username'][0].upper()}
                    </div>
                    <div class="user-info">
                        <div style="font-weight: bold">
                            {user['username']}
                            <span class="status-badge {status_class}">
                                {status_text}
                            </span>
                        </div>
                        <div class="meta-info">
                            ID: {user['chatId']} | Create at: {datetime.fromisoformat(user['createdAt'].replace('Z', '+00:00')).strftime("%d-%m-%Y %H:%M:%S")}
                        </div>
                    </div>
                </div>
            """

    # Thêm JavaScript để xử lý click event
    html_content += """
            </div>
        </div>
        """
    html(html_content)
    cid=bridge('click-id', "")
    if cid != "":
        usrn(cid)
    st.button("Add User", on_click=add_user)
except Exception as e:
    st.error(f"Error fetching users: {str(e)}")
  • main.py
import streamlit as st
from src.credentials import logout, check_logged_in, login_form

if check_logged_in():
    st.navigation([
        st.Page("src/users.py"),
        st.Page("src/groups.py"),
        st.Page("src/keys.py"),
    ], position="hidden").run()
    with st.sidebar:
        st.page_link("src/users.py", label="Users")
        st.page_link("src/groups.py", label="Groups")
        st.page_link("src/keys.py", label="Keys")
        if st.button("Logout"):
            logout()
            st.rerun()
elif login_form():  # Nếu login thành công
    st.rerun()

khi mình thử test.py với dữ liệu mẫu thì nó vẫn chạy bình thường

  • test.py
import streamlit as st
from datetime import datetime
from st_bridge import html, bridge

# Data mẫu
data = {
    "content": [
        {
            "chatId": 1813442391,
            "username": "afewsfga",
            "createdAt": "2025-02-07T10:29:09.486299",
            "balance": 0,
            "status": 1
        },
        {
            "chatId": 1,
            "username": "test",
            "createdAt": "2025-02-10T04:54:20.696043",
            "balance": 0,
            "status": 1
        }
    ],
    "totalElements": 2,
    "number": 0,
    "totalPages": 1,
    "numberOfElements": 2
}

def format_datetime(dt_str):
    dt = datetime.fromisoformat(dt_str.replace('Z', '+00:00'))
    return dt.strftime("%d-%m-%Y %H:%M:%S")

# Khởi tạo session state
if 'selected_user' not in st.session_state:
    st.session_state.selected_user = None

# Tạo HTML component
html_content = """
<style>
    .container {
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    }
    .user-list {
        max-width: 800px;
        margin: 0 auto;
    }
    .user-item {
        display: flex;
        align-items: center;
        padding: 15px;
        margin: 8px 0;
        border: 1px solid #ddd;
        border-radius: 8px;
        cursor: pointer;
        transition: all 0.3s;
        background-color: white;
    }
    .user-item:hover {
        background-color: #f8f9fa;
        transform: translateX(5px);
        box-shadow: 0 2px 5px rgba(0,0,0,0.1);
    }
    .avatar {
        width: 45px;
        height: 45px;
        border-radius: 50%;
        display: flex;
        align-items: center;
        justify-content: center;
        color: white;
        font-weight: bold;
        margin-right: 15px;
        background-color: #0066cc;
    }
    .user-info {
        flex-grow: 1;
    }
    .status-badge {
        padding: 4px 8px;
        border-radius: 12px;
        color: white;
        font-size: 0.8em;
        margin-left: 10px;
    }
    .meta-info {
        color: #666;
        font-size: 0.9em;
        margin-top: 4px;
    }
    .active {
        background-color: #28a745;
    }
    .inactive {
        background-color: #dc3545;
    }
</style>

<div class="container">
    <div class="user-list">
"""

# Thêm user items vào HTML
for user in data['content']:
    status_class = "active" if user['status'] == 1 else "inactive"
    status_text = "Active" if user['status'] == 1 else "Inactive"

    html_content += f"""
        <div class="user-item" onclick="stBridges.send('click-id', {user['chatId']})">
            <div class="avatar">
                {user['username'][0].upper()}
            </div>
            <div class="user-info">
                <div style="font-weight: bold">
                    {user['username']}
                    <span class="status-badge {status_class}">
                        {status_text}
                    </span>
                </div>
                <div class="meta-info">
                    ID: {user['chatId']} | Create at: {format_datetime(user['createdAt'])}
                </div>
            </div>
        </div>
    """

# Thêm JavaScript để xử lý click event
html_content += """
    </div>
</div>
"""

@st.dialog("Thông tin người dùng")
def usrn():
    st.write(f"Username: {data["content"][cid]["username"]}")

cid = bridge('click-id', "")
if cid != "":
    usrn()

# Render HTML component
html(html_content)

ayclqt avatar Feb 10 '25 08:02 ayclqt

Hi there, thanks for reporting and sharing the code. However, I’m facing some issues in reproducing it since it’s missing certain files, such as credentials and config. Could you kindly create some dummy code for these files? That would help me a lot in resolving this problem. Thanks.

binh-vu avatar Feb 16 '25 19:02 binh-vu