Spaces:
Paused
Paused
Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import dash
|
| 2 |
+
from dash import dcc, html, Input, Output, State, callback
|
| 3 |
+
import dash_bootstrap_components as dbc
|
| 4 |
+
import uuid
|
| 5 |
+
import sqlite3
|
| 6 |
+
|
| 7 |
+
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
|
| 8 |
+
|
| 9 |
+
# Initialize SQLite database
|
| 10 |
+
conn = sqlite3.connect('links.db', check_same_thread=False)
|
| 11 |
+
c = conn.cursor()
|
| 12 |
+
|
| 13 |
+
# Create table if it doesn't exist
|
| 14 |
+
c.execute('''CREATE TABLE IF NOT EXISTS links
|
| 15 |
+
(id TEXT PRIMARY KEY, name TEXT, url TEXT)''')
|
| 16 |
+
conn.commit()
|
| 17 |
+
|
| 18 |
+
# Function to get all links from the database
|
| 19 |
+
def get_links():
|
| 20 |
+
c.execute("SELECT * FROM links")
|
| 21 |
+
return [{"id": row[0], "name": row[1], "url": row[2]} for row in c.fetchall()]
|
| 22 |
+
|
| 23 |
+
# Initialize with some example URLs if the table is empty
|
| 24 |
+
if not get_links():
|
| 25 |
+
initial_urls = [
|
| 26 |
+
{"id": str(uuid.uuid4()), "name": "Google", "url": "https://www.google.com"},
|
| 27 |
+
{"id": str(uuid.uuid4()), "name": "Bing", "url": "https://www.bing.com"},
|
| 28 |
+
]
|
| 29 |
+
c.executemany("INSERT INTO links VALUES (:id, :name, :url)", initial_urls)
|
| 30 |
+
conn.commit()
|
| 31 |
+
|
| 32 |
+
app.layout = dbc.Container([
|
| 33 |
+
dbc.Row([
|
| 34 |
+
# Left navigation column
|
| 35 |
+
dbc.Col([
|
| 36 |
+
html.H2("My URL App", className="mt-3 mb-4"),
|
| 37 |
+
html.Div(id='url-list'),
|
| 38 |
+
dbc.Input(id='new-url-name', placeholder="New URL Name", className="mb-2"),
|
| 39 |
+
dbc.Input(id='new-url-link', placeholder="New URL", className="mb-2"),
|
| 40 |
+
dbc.Button("Add URL", id='add-url-button', color="primary", className="mb-3"),
|
| 41 |
+
], width=3, className="bg-light p-3"),
|
| 42 |
+
|
| 43 |
+
# Main content column with iframe
|
| 44 |
+
dbc.Col([
|
| 45 |
+
html.Iframe(id='content-iframe', style={'width': '100%', 'height': '800px'})
|
| 46 |
+
], width=9)
|
| 47 |
+
])
|
| 48 |
+
], fluid=True)
|
| 49 |
+
|
| 50 |
+
@callback(
|
| 51 |
+
Output('url-list', 'children'),
|
| 52 |
+
Input('add-url-button', 'n_clicks'),
|
| 53 |
+
State('new-url-name', 'value'),
|
| 54 |
+
State('new-url-link', 'value')
|
| 55 |
+
)
|
| 56 |
+
def update_url_list(n_clicks, new_name, new_link):
|
| 57 |
+
ctx = dash.callback_context
|
| 58 |
+
if ctx.triggered_id == 'add-url-button' and new_name and new_link:
|
| 59 |
+
new_id = str(uuid.uuid4())
|
| 60 |
+
c.execute("INSERT INTO links VALUES (?, ?, ?)", (new_id, new_name, new_link))
|
| 61 |
+
conn.commit()
|
| 62 |
+
|
| 63 |
+
links = get_links()
|
| 64 |
+
return [
|
| 65 |
+
dbc.Button(
|
| 66 |
+
link['name'],
|
| 67 |
+
id={'type': 'url-button', 'index': link['id']},
|
| 68 |
+
color="link",
|
| 69 |
+
className="d-block text-left mb-2"
|
| 70 |
+
) for link in links
|
| 71 |
+
] + [
|
| 72 |
+
dbc.Button(
|
| 73 |
+
"Delete",
|
| 74 |
+
id={'type': 'delete-button', 'index': link['id']},
|
| 75 |
+
color="danger",
|
| 76 |
+
size="sm",
|
| 77 |
+
className="mr-2 mb-2"
|
| 78 |
+
) for link in links
|
| 79 |
+
]
|
| 80 |
+
|
| 81 |
+
@callback(
|
| 82 |
+
Output('content-iframe', 'src'),
|
| 83 |
+
Input({'type': 'url-button', 'index': dash.ALL}, 'n_clicks')
|
| 84 |
+
)
|
| 85 |
+
def update_iframe(n_clicks):
|
| 86 |
+
ctx = dash.callback_context
|
| 87 |
+
if not ctx.triggered:
|
| 88 |
+
return dash.no_update
|
| 89 |
+
button_id = ctx.triggered[0]['prop_id'].split('.')[0]
|
| 90 |
+
clicked_id = eval(button_id)['index']
|
| 91 |
+
c.execute("SELECT url FROM links WHERE id = ?", (clicked_id,))
|
| 92 |
+
result = c.fetchone()
|
| 93 |
+
if result:
|
| 94 |
+
return result[0]
|
| 95 |
+
return dash.no_update
|
| 96 |
+
|
| 97 |
+
@callback(
|
| 98 |
+
Output('url-list', 'children', allow_duplicate=True),
|
| 99 |
+
Input({'type': 'delete-button', 'index': dash.ALL}, 'n_clicks'),
|
| 100 |
+
prevent_initial_call=True
|
| 101 |
+
)
|
| 102 |
+
def delete_url(n_clicks):
|
| 103 |
+
ctx = dash.callback_context
|
| 104 |
+
if not ctx.triggered:
|
| 105 |
+
return dash.no_update
|
| 106 |
+
button_id = ctx.triggered[0]['prop_id'].split('.')[0]
|
| 107 |
+
delete_id = eval(button_id)['index']
|
| 108 |
+
c.execute("DELETE FROM links WHERE id = ?", (delete_id,))
|
| 109 |
+
conn.commit()
|
| 110 |
+
return update_url_list(None, None, None)
|
| 111 |
+
|
| 112 |
+
if __name__ == '__main__':
|
| 113 |
+
print("Starting the Dash application...")
|
| 114 |
+
app.run(debug=True, host='0.0.0.0', port=7860)
|
| 115 |
+
print("Dash application has finished running.")
|