Skip to content

feat: field template manager#1374

Open
TrigamDev wants to merge 11 commits into
TagStudioDev:mainfrom
TrigamDev:feat/field_manager
Open

feat: field template manager#1374
TrigamDev wants to merge 11 commits into
TagStudioDev:mainfrom
TrigamDev:feat/field_manager

Conversation

@TrigamDev
Copy link
Copy Markdown
Collaborator

@TrigamDev TrigamDev commented May 15, 2026

Summary

  • Replaces the field template chooser with one similar to the tag chooser, and adds a field template manager modal.
    • To do this, the tag chooser and tag managers have been merged, split into a view and controller, and had most functionality made generic (creating a SearchPanel and SearchPanelView). The new FieldTemplateSearchPanel and FieldTemplateSearchPanelView extend from these new classes.
  • To better match the tag. translation keys that the tag search panel uses, the library.field. translation keys have been changed to field..
  • Several new field. translation keys have been added to be used by the field template search panel.
  • en has been correctly sorted (I ran a JSON sorter on it to make sure the new keys were correctly sorted, and found that existing keys weren't correctly sorted).

Note

This pull request does NOT implement creating, editing, or deleting field templates. Some inputs, such as "Create" buttons, are visible, but do nothing when interacted with.

image

Tasks Completed

  • Platforms Tested:
    • Windows x86
    • Windows ARM
    • macOS x86
    • macOS ARM
    • Linux x86
    • Linux ARM
  • Tested For:
    • Basic functionality
    • PyInstaller executable

@TrigamDev TrigamDev added Type: Enhancement New feature or request Type: Refactor Code that needs to be restructured or cleaned up Type: UI/UX User interface and/or user experience TagStudio: Library Relating to the TagStudio library system Type: Translations Modifies translation keys or translation capabilities. Status: Review Needed A review of this is needed labels May 15, 2026
@TrigamDev TrigamDev changed the title feat: field manager feat: field template manager May 15, 2026
@CyanVoxel CyanVoxel added Priority: Medium An issue that shouldn't be be saved for last Note: Sync Weblate Before Pulling Indicates that the Weblate translations repository needs to be up to date before pulling this code. labels May 17, 2026
@CyanVoxel CyanVoxel added this to the Alpha v9.6.0 milestone May 17, 2026
@CyanVoxel CyanVoxel moved this to 👀 In review in TagStudio Development May 17, 2026
Copy link
Copy Markdown
Member

@CyanVoxel CyanVoxel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your work on this so far!
Besides my comments here, you've seen from the Discord that I have great concerns about our current MVC recommendation that encourages controller classes to inherit from views now that we're moving beyond simple use cases. Now that you're doing the (correct) thing and looking to reduce code duplication with our old widgets, its exposed the issues with doing this from an inheritance perspective.

To briefly reiterate and to have a record here, the following type of class structure caused by our current MVC implementation recommendation:

class FieldTemplateSearchPanel(SearchPanel[BaseFieldTemplate], FieldTemplateSearchPanelView):
    ...

Causes a tangled tree of unsafe and duplicated multiple inheritance:

FieldTemplateSearchPanel(C) <- SearchPanel(C) <- SearchPanelView(V) <- PanelWidget(V) <- QWidget
                            ^- FieldTemplateSearchPanelView(V) <- SearchPanelView(V) <- PanelWidget(V) <- QWidget

While a more traditional approach of composing the view and controller together would eliminate all inheritance issues and code reuse hurdles while not sacrificing any functionality:

class FieldTemplateSearchPanel(): # Controller
    def __init__(self, view=FieldTemplateSearchPanelView):
        ...
FieldTemplateSearchPanelView(V) <- SearchPanelView(V) <- PanelWidget(V) <- QWidget
    FieldTemplateSearchPanel(C) <- SearchPanel©

Passing a view to a controller's constructor and keeping a reference when needed should retain the functionality and simplicity afforded by our current recommendation but without any of the inheritance issues brought to light here.

Frankly I don't have too much of a preference as to whether or not we have the view composed in the controller or the controller composed in the view, I just know that the examples I've found do the later and it's closer to what we currently recommend. I just don't want to be caught several months into another UI refactor just to reach a point where we realize we need to refactor again due to an unexpected roadblock with our approach. If you have specific concerns about that approach or see benefits from the inverse, please let me know here.

I'd just hold off on doing a new refactor until a consensus is reached between us and @Computerdores on how to implement MVC moving forward, but it's something I do anticipate on changing in the near future. In the meantime I'm open to at least pulling this PR as it seems to at least function for the time being, and is required to unblock #1358 and #1359 for the upcoming 9.6.0 update.

def __init__(
self,
library: Library,
exclude: Sequence[BaseFieldTemplate] | None = None,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlike tags, fields don't have the assumption that there should only be one of each at most on an entry, so it shouldn't be necessary to have exclusion logic for them

exclude: Sequence[BaseFieldTemplate] | None = None,
is_field_template_chooser: bool = True,
) -> None:
super().__init__([], is_field_template_chooser)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend explicitly calling the base classes' __init__() methods rather than using super() when using multiple inheritance for the reasons described here

Suggested change
super().__init__([], is_field_template_chooser)
SearchPanel.__init__(self, [], is_field_template_chooser)
FieldTemplateSearchPanelView.__init__(self, is_field_template_chooser)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explicitly calling the base classes' __init__() results in SearchPanelView being initialized twice and triggering a crash

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dang, I must've forgotten about that when I was originally reviewing this a few days ago. I think the basedpyright error led me to this and then that crash led me to look into the init calls further and discover the issues with the inheritance tree.

Disregard these recommendations then, but the underlying issue with the super() call and inheritance tree is still present.

Comment thread src/tagstudio/qt/controllers/tag_search_panel_controller.py
Comment thread pyproject.toml
[tool.pytest.ini_options]
#addopts = "-m 'not qt'"
qt_api = "pyside6"
pythonpath = ["src"]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was having some issues with pytest not recognizing new files, and adding this line fixed it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I've noticed that whatever sorting method you (and Weblate) are using for the translation keys is more accurate than the built-in "Sort Lines Ascending" function in VS Code for me. What are you using to sort these?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Note: Sync Weblate Before Pulling Indicates that the Weblate translations repository needs to be up to date before pulling this code. Priority: Medium An issue that shouldn't be be saved for last Status: Review Needed A review of this is needed TagStudio: Library Relating to the TagStudio library system Type: Enhancement New feature or request Type: Refactor Code that needs to be restructured or cleaned up Type: Translations Modifies translation keys or translation capabilities. Type: UI/UX User interface and/or user experience

Projects

Status: 👀 In review

Development

Successfully merging this pull request may close these issues.

2 participants