Recover from git cockup: reimplement template management

This commit is contained in:
Keith Edmunds 2024-12-29 18:34:44 +00:00
parent a8931e8b2b
commit 68e524594d
5 changed files with 160 additions and 6 deletions

View File

@ -73,7 +73,6 @@ class PlaylistsTable(Model):
tab: Mapped[Optional[int]] = mapped_column(default=None)
open: Mapped[bool] = mapped_column(default=False)
is_template: Mapped[bool] = mapped_column(default=False)
deleted: Mapped[bool] = mapped_column(default=False)
rows: Mapped[List["PlaylistRowsTable"]] = relationship(
"PlaylistRowsTable",
back_populates="playlist",

View File

@ -225,10 +225,10 @@ class Playlists(dbtables.PlaylistsTable):
def delete(self, session: Session) -> None:
"""
Mark as deleted
Delete playlist
"""
self.deleted = True
session.execute(delete(Playlists).where(Playlists.id == self.id))
session.commit()
@classmethod

View File

@ -51,6 +51,7 @@ import stackprinter # type: ignore
# App imports
from classes import (
ApplicationError,
MusicMusterSignals,
TrackInfo,
)
@ -96,6 +97,64 @@ class Current:
)
class EditDeleteDialog(QDialog):
def __init__(self, templates: list[tuple[str, int]]) -> None:
super().__init__()
self.templates = templates
self.selection: tuple[str, int] = ("", -1)
self.init_ui()
def init_ui(self) -> None:
# Create label
label = QLabel("Select template:")
# Create combo box
self.combo_box = QComboBox()
for text, id_ in self.templates:
self.combo_box.addItem(text, id_)
# Create buttons
edit_button = QPushButton("Edit")
delete_button = QPushButton("Delete")
cancel_button = QPushButton("Cancel")
# Connect buttons
edit_button.clicked.connect(self.edit_clicked)
delete_button.clicked.connect(self.delete_clicked)
cancel_button.clicked.connect(self.cancel_clicked)
# Layout setup
top_layout = QHBoxLayout()
top_layout.addWidget(label)
top_layout.addWidget(self.combo_box)
bottom_layout = QHBoxLayout()
bottom_layout.addStretch()
bottom_layout.addWidget(edit_button)
bottom_layout.addWidget(delete_button)
bottom_layout.addWidget(cancel_button)
main_layout = QVBoxLayout()
main_layout.addLayout(top_layout)
main_layout.addLayout(bottom_layout)
self.setLayout(main_layout)
self.setWindowTitle("Edit or Delete Template")
def edit_clicked(self) -> None:
self.selection = ("Edit", self.combo_box.currentData())
self.accept()
def delete_clicked(self) -> None:
self.selection = ("Delete", self.combo_box.currentData())
self.accept()
def cancel_clicked(self) -> None:
self.selection = ("Cancelled", -1)
self.reject()
class PreviewManager:
"""
Manage track preview player
@ -803,8 +862,12 @@ class Window(QMainWindow, Ui_MainWindow):
dlg.resize(500, 100)
ok = dlg.exec()
if ok:
if self.current.selected_rows:
new_row_number = self.current.selected_rows[0]
else:
new_row_number = self.current.base_model.rowCount()
self.current.base_model.insert_row(
proposed_row_number=self.current.selected_rows[0],
proposed_row_number=new_row_number,
note=dlg.textValue(),
)
@ -870,6 +933,46 @@ class Window(QMainWindow, Ui_MainWindow):
self.signals.search_wikipedia_signal.emit(track_info.title)
def manage_templates(self) -> None:
"""
Delete / edit templates
"""
# Build a list of (template-name, playlist-id) tuples
template_list: list[tuple[str, int]] = []
with db.Session() as session:
for template in Playlists.get_all_templates(session):
template_list.append((template.name, template.id))
# Get user's selection
dlg = EditDeleteDialog(template_list)
if not dlg.exec():
return # User cancelled
action, template_id = dlg.selection
playlist = session.get(Playlists, template_id)
if not playlist:
log.error(f"Error opening {template_id=}")
if action == "Edit":
# Simply load the template as a playlist. Any changes
# made will persist
idx = self.create_playlist_tab(playlist)
self.tabPlaylist.setCurrentIndex(idx)
elif action == "Delete":
if helpers.ask_yes_no(
"Delete template",
f"Delete template '{playlist.name}': " "Are you sure?",
):
if self.close_playlist_tab():
playlist.delete(session)
session.commit()
else:
raise ApplicationError(f"Unrecognised action from EditDeleteDialog: {action=}")
def mark_rows_for_moving(self) -> None:
"""
Cut rows ready for pasting.

View File

@ -677,5 +677,5 @@ class Ui_MainWindow(object):
self.actionSearch_title_in_Songfacts.setShortcut(_translate("MainWindow", "Ctrl+S"))
self.actionSelect_duplicate_rows.setText(_translate("MainWindow", "Select duplicate rows..."))
self.actionReplace_files.setText(_translate("MainWindow", "Import files..."))
from infotabs import InfoTabs
from pyqtgraph import PlotWidget
from infotabs import InfoTabs # type: ignore
from pyqtgraph import PlotWidget # type: ignore

View File

@ -0,0 +1,52 @@
"""Remove playlists.delete and implement Cascade deletes
Revision ID: 33c04e3c12c8
Revises: 164bd5ef3074
Create Date: 2024-12-29 17:56:00.627198
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
# revision identifiers, used by Alembic.
revision = '33c04e3c12c8'
down_revision = '164bd5ef3074'
branch_labels = None
depends_on = None
def upgrade(engine_name: str) -> None:
globals()["upgrade_%s" % engine_name]()
def downgrade(engine_name: str) -> None:
globals()["downgrade_%s" % engine_name]()
def upgrade_() -> None:
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('playlist_rows', schema=None) as batch_op:
batch_op.drop_constraint('playlist_rows_ibfk_3', type_='foreignkey')
batch_op.create_foreign_key('playlist_rows_ibfk_3', 'playlists', ['playlist_id'], ['id'], ondelete='CASCADE')
with op.batch_alter_table('playlists', schema=None) as batch_op:
batch_op.drop_column('deleted')
# ### end Alembic commands ###
def downgrade_() -> None:
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('playlists', schema=None) as batch_op:
batch_op.add_column(sa.Column('deleted', mysql.TINYINT(display_width=1), autoincrement=False, nullable=False))
with op.batch_alter_table('playlist_rows', schema=None) as batch_op:
batch_op.drop_constraint(None, type_='foreignkey')
batch_op.create_foreign_key(None, 'playlists', ['playlist_id'], ['id'])
# ### end Alembic commands ###