import dash from dash import dcc, html, Input, Output, State, callback import dash_bootstrap_components as dbc import uuid import sqlite3 app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP]) DB_FILE = 'links.db' def get_db_connection(): conn = sqlite3.connect(DB_FILE, check_same_thread=False) conn.row_factory = sqlite3.Row return conn def init_db(): try: conn = get_db_connection() c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS links (id TEXT PRIMARY KEY, name TEXT, url TEXT)''') conn.commit() print("Database initialized successfully") except Exception as e: print(f"Error initializing database: {e}") finally: conn.close() init_db() def get_links(): try: conn = get_db_connection() c = conn.cursor() c.execute("SELECT * FROM links") links = [dict(row) for row in c.fetchall()] print(f"Retrieved links: {links}") # Debug print return links except Exception as e: print(f"Error retrieving links: {e}") return [] finally: conn.close() def generate_url_list(links): url_list = [ dbc.ListGroupItem([ dbc.Button( link['name'], id={'type': 'url-button', 'index': link['id']}, color="link", className="text-left" ), html.Span( "✕", id={'type': 'delete-button', 'index': link['id']}, className="float-right text-danger", style={"cursor": "pointer"} ) ], className="d-flex justify-content-between align-items-center") for link in links ] print(f"Generated URL list: {url_list}") # Debug print return url_list app.layout = dbc.Container([ dcc.Store(id='add-url-status', data=''), dcc.Store(id='trigger-load', data='load'), # New store to trigger initial load dbc.Modal([ dbc.ModalHeader("Add New URL"), dbc.ModalBody([ dbc.Input(id='new-url-name', placeholder="URL Name", className="mb-2"), dbc.Input(id='new-url-link', placeholder="URL", className="mb-2"), html.Div(id='add-url-feedback') ]), dbc.ModalFooter( dbc.Button("Add", id="add-url-button", className="ml-auto") ), ], id="add-url-modal"), dbc.Row([ dbc.Col([ html.H2("My URL App", className="mt-3 mb-4"), dbc.Button("Add URL", id="open-modal-button", color="primary", className="mb-3"), html.Div(id='url-list'), ], width=3, className="bg-light p-3"), dbc.Col([ html.Iframe( id='content-iframe', style={'width': '100%', 'height': '800px'}, sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-downloads", allow="fullscreen; geolocation; microphone; camera; midi; encrypted-media; autoplay", referrerPolicy="no-referrer" ) ], width=9) ]) ], fluid=True) @callback( [Output("add-url-modal", "is_open"), Output('new-url-name', 'value'), Output('new-url-link', 'value')], [Input("open-modal-button", "n_clicks"), Input("add-url-button", "n_clicks")], [State("add-url-modal", "is_open")], ) def toggle_modal(n1, n2, is_open): if n1 or n2: if is_open: return False, '', '' # Close modal and reset input fields return True, dash.no_update, dash.no_update # Open modal return is_open, dash.no_update, dash.no_update @callback( [Output('url-list', 'children'), Output('add-url-feedback', 'children'), Output('add-url-status', 'data')], [Input('trigger-load', 'data'), Input('add-url-button', 'n_clicks'), Input({'type': 'delete-button', 'index': dash.ALL}, 'n_clicks')], [State('new-url-name', 'value'), State('new-url-link', 'value')], prevent_initial_call=False ) def update_url_list(trigger_load, add_clicks, delete_clicks, new_name, new_link): ctx = dash.callback_context if not ctx.triggered: raise dash.exceptions.PreventUpdate triggered_id = ctx.triggered[0]['prop_id'].split('.')[0] print(f"Triggered by: {triggered_id}") # Debug print feedback = None status = '' if triggered_id == 'trigger-load': print("Initial load triggered") elif triggered_id == 'add-url-button' and new_name and new_link: try: conn = get_db_connection() c = conn.cursor() new_id = str(uuid.uuid4()) c.execute("INSERT INTO links VALUES (?, ?, ?)", (new_id, new_name, new_link)) conn.commit() print(f"Added new URL: {new_name}, {new_link}") # Debug print feedback = html.Div("URL added successfully!", style={'color': 'green'}) status = 'added' except Exception as e: print(f"Error adding URL: {e}") feedback = html.Div("Error adding URL. Please try again.", style={'color': 'red'}) status = 'error' finally: conn.close() elif 'delete-button' in triggered_id: delete_id = eval(triggered_id)['index'] try: conn = get_db_connection() c = conn.cursor() c.execute("DELETE FROM links WHERE id = ?", (delete_id,)) conn.commit() print(f"Deleted URL with id: {delete_id}") # Debug print feedback = html.Div("URL deleted successfully!", style={'color': 'green'}) status = 'deleted' except Exception as e: print(f"Error deleting URL: {e}") feedback = html.Div("Error deleting URL. Please try again.", style={'color': 'red'}) status = 'error' finally: conn.close() links = get_links() url_list = generate_url_list(links) return url_list, feedback, status @callback( Output('content-iframe', 'src'), Input({'type': 'url-button', 'index': dash.ALL}, 'n_clicks') ) def update_iframe(n_clicks): ctx = dash.callback_context if not ctx.triggered: return dash.no_update button_id = ctx.triggered[0]['prop_id'].split('.')[0] clicked_id = eval(button_id)['index'] try: conn = get_db_connection() c = conn.cursor() c.execute("SELECT url FROM links WHERE id = ?", (clicked_id,)) result = c.fetchone() if result: print(f"Loading URL: {result['url']}") # Debug print return result['url'] except Exception as e: print(f"Error loading URL: {e}") finally: conn.close() # This line was likely causing the IndentationError return dash.no_update if __name__ == '__main__': print("Starting the Dash application...") app.run(debug=True, host='0.0.0.0', port=7860) print("Dash application has finished running.")