PCM: add ability to pin packages

Pinned packages don't affect available update notification and will not
be updated with "Update All" button. Manual update is still possible but
will trigger a confirmation dialog.
This commit is contained in:
qu1ck 2022-08-28 04:40:06 -07:00 committed by Seth Hillbrand
parent f6b1ff821b
commit 977b6cd8f3
12 changed files with 226 additions and 66 deletions

View File

@ -88,6 +88,13 @@ void SPLIT_BUTTON::SetBitmap( const wxBitmap& aBmp )
}
void SPLIT_BUTTON::SetLabel( const wxString& aLabel )
{
m_label = aLabel;
Refresh();
}
wxMenu* SPLIT_BUTTON::GetSplitButtonMenu()
{
return m_pMenu;

View File

@ -43,6 +43,7 @@ public:
void SetBitmap( const wxBitmap& aBmp );
void SetMinSize( const wxSize& aSize ) override;
void SetWidthPadding( int aPadding );
void SetLabel( const wxString& aLabel ) override;
protected:
void OnKillFocus( wxFocusEvent& aEvent );

View File

@ -66,23 +66,19 @@ DIALOG_PCM::DIALOG_PCM( wxWindow* parent, std::shared_ptr<PLUGIN_CONTENT_MANAGER
m_discardActionButton->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
m_panelPending->Layout();
m_installedPanel = new PANEL_PACKAGES_VIEW( m_panelInstalledHolder, m_pcm );
m_panelInstalledHolder->GetSizer()->Add( m_installedPanel, 1, wxEXPAND );
m_panelInstalledHolder->Layout();
for( const std::pair<PCM_PACKAGE_TYPE, wxString>& entry : PACKAGE_TYPE_LIST )
m_actionCallback = [this]( const PACKAGE_VIEW_DATA& aData, PCM_PACKAGE_ACTION aAction,
const wxString& aVersion )
{
PANEL_PACKAGES_VIEW* panel = new PANEL_PACKAGES_VIEW( m_contentNotebook, m_pcm );
wxString label = wxGetTranslation( entry.second );
m_contentNotebook->AddPage( panel, wxString::Format( label, 0 ) );
m_repositoryContentPanels.insert( { entry.first, panel } );
}
if( aAction == PPA_UPDATE && m_pcm->IsPackagePinned( aData.package.identifier ) )
{
if( wxMessageBox( wxString::Format( _( "Are you sure you want to update pinned package "
"from version %s to %s?" ),
aData.current_version, aVersion ),
_( "Confirm update" ), wxICON_QUESTION | wxYES_NO, this )
== wxNO )
return;
}
m_dialogNotebook->SetPageText( 0, wxString::Format( _( "Repository (%d)" ), 0 ) );
m_callback = [this]( const PACKAGE_VIEW_DATA& aData, PCM_PACKAGE_ACTION aAction,
const wxString& aVersion )
{
m_gridPendingActions->Freeze();
PCM_PACKAGE_STATE new_state;
@ -125,12 +121,33 @@ DIALOG_PCM::DIALOG_PCM( wxWindow* parent, std::shared_ptr<PLUGIN_CONTENT_MANAGER
updatePendingActionsTab();
m_installedPanel->SetPackageState( aData.package.identifier, new_state );
for( const auto& entry : m_repositoryContentPanels )
entry.second->SetPackageState( aData.package.identifier, new_state );
updatePackageState( aData.package.identifier, new_state );
};
m_pinCallback =
[this]( const wxString& aPackageId, const PCM_PACKAGE_STATE aState, const bool aPinned )
{
m_pcm->SetPinned( aPackageId, aPinned );
updatePackageState( aPackageId, aState );
};
m_installedPanel = new PANEL_PACKAGES_VIEW( m_panelInstalledHolder, m_pcm, m_actionCallback,
m_pinCallback );
m_panelInstalledHolder->GetSizer()->Add( m_installedPanel, 1, wxEXPAND );
m_panelInstalledHolder->Layout();
for( const std::pair<PCM_PACKAGE_TYPE, wxString>& entry : PACKAGE_TYPE_LIST )
{
PANEL_PACKAGES_VIEW* panel = new PANEL_PACKAGES_VIEW( m_contentNotebook, m_pcm,
m_actionCallback, m_pinCallback );
wxString label = wxGetTranslation( entry.second );
m_contentNotebook->AddPage( panel, wxString::Format( label, 0 ) );
m_repositoryContentPanels.insert( { entry.first, panel } );
}
m_dialogNotebook->SetPageText( 0, wxString::Format( _( "Repository (%d)" ), 0 ) );
setInstalledPackages();
updatePendingActionsTab();
@ -312,7 +329,10 @@ void DIALOG_PCM::setRepositoryData( const wxString& aRepositoryId )
package_data.state = m_pcm->GetPackageState( aRepositoryId, pkg.identifier );
if( package_data.state == PPS_INSTALLED || package_data.state == PPS_UPDATE_AVAILABLE )
{
package_data.current_version = m_pcm->GetInstalledPackageVersion( pkg.identifier );
package_data.pinned = m_pcm->IsPackagePinned( pkg.identifier );
}
if( package_data.state == PPS_UPDATE_AVAILABLE )
package_data.update_version = m_pcm->GetPackageUpdateVersion( pkg );
@ -343,7 +363,7 @@ void DIALOG_PCM::setRepositoryData( const wxString& aRepositoryId )
{
PCM_PACKAGE_TYPE type = PACKAGE_TYPE_LIST[i].first;
const wxString& label = PACKAGE_TYPE_LIST[i].second;
m_repositoryContentPanels[type]->SetData( data[type], m_callback );
m_repositoryContentPanels[type]->SetData( data[type] );
m_contentNotebook->SetPageText(
i, wxString::Format( wxGetTranslation( label ), (int) data[type].size() ) );
}
@ -401,7 +421,7 @@ void DIALOG_PCM::setInstalledPackages()
package_list.emplace_back( package_data );
}
m_installedPanel->SetData( package_list, m_callback );
m_installedPanel->SetData( package_list );
m_dialogNotebook->SetPageText(
1, wxString::Format( _( "Installed (%d)" ), (int) package_list.size() ) );
@ -489,15 +509,23 @@ void DIALOG_PCM::discardAction( int aIndex )
PCM_PACKAGE_STATE state =
m_pcm->GetPackageState( action.repository_id, action.package.identifier );
m_installedPanel->SetPackageState( action.package.identifier, state );
for( const auto& entry : m_repositoryContentPanels )
entry.second->SetPackageState( action.package.identifier, state );
updatePackageState( action.package.identifier, state );
m_pendingActions.erase( m_pendingActions.begin() + aIndex );
}
void DIALOG_PCM::updatePackageState( const wxString& aPackageId, const PCM_PACKAGE_STATE aState )
{
bool pinned = m_pcm->IsPackagePinned( aPackageId );
m_installedPanel->SetPackageState( aPackageId, aState, pinned );
for( const auto& entry : m_repositoryContentPanels )
entry.second->SetPackageState( aPackageId, aState, pinned );
}
void DIALOG_PCM::OnOpenPackageDirClicked( wxCommandEvent& event )
{
LaunchExternal( m_pcm->Get3rdPartyPath() );

View File

@ -90,11 +90,15 @@ private:
///< Gets installed packages list from PCM and displays it on installed tab
void setInstalledPackages();
///< Reflects new state of the package in all panels where it is displayed
void updatePackageState( const wxString& aPackageId, const PCM_PACKAGE_STATE aState );
///< Discards specified pending action
void discardAction( int aIndex );
std::shared_ptr<PLUGIN_CONTENT_MANAGER> m_pcm;
ActionCallback m_callback;
ActionCallback m_actionCallback;
PinCallback m_pinCallback;
PANEL_PACKAGES_VIEW* m_installedPanel;
std::unordered_map<PCM_PACKAGE_TYPE, PANEL_PACKAGES_VIEW*> m_repositoryContentPanels;
wxString m_selectedRepositoryId;

View File

@ -24,9 +24,9 @@
#include "panel_package.h"
PANEL_PACKAGE::PANEL_PACKAGE( wxWindow* parent, const ActionCallback& aCallback,
const PACKAGE_VIEW_DATA& aData ) :
const PinCallback& aPinCallback, const PACKAGE_VIEW_DATA& aData ) :
PANEL_PACKAGE_BASE( parent ),
m_actionCallback( aCallback ), m_data( aData )
m_actionCallback( aCallback ), m_pinCallback( aPinCallback ), m_data( aData )
{
// Propagate clicks on static elements to the panel handler.
m_name->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( PANEL_PACKAGE::OnClick ), NULL, this );
@ -60,13 +60,18 @@ PANEL_PACKAGE::PANEL_PACKAGE( wxWindow* parent, const ActionCallback& aCallback,
m_splitButton->SetLabel( _( "Update" ) );
m_splitButton->Bind( wxEVT_BUTTON, &PANEL_PACKAGE::OnButtonClicked, this );
wxMenu* splitMenu = m_splitButton->GetSplitButtonMenu();
wxMenuItem* menuItem = splitMenu->Append( wxID_ANY, _( "Uninstall" ) );
wxMenu* splitMenu = m_splitButton->GetSplitButtonMenu();
m_pinVersionMenuItem =
splitMenu->Append( wxID_ANY, _( "Pin package" ),
_( "Pinned packages don't affect available update notification and "
"will not be updated with \"Update All\" button." ),
wxITEM_CHECK );
splitMenu->Bind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_PACKAGE::OnPinVersionClick, this,
m_pinVersionMenuItem->GetId() );
splitMenu->Bind( wxEVT_COMMAND_MENU_SELECTED, &PANEL_PACKAGE::OnUninstallClick, this,
menuItem->GetId() );
m_actionMenuItem = splitMenu->Append( wxID_ANY, _( "Uninstall" ) );
SetState( m_data.state );
SetState( m_data.state, m_data.pinned );
}
@ -76,9 +81,11 @@ void PANEL_PACKAGE::OnSize( wxSizeEvent& event )
}
void PANEL_PACKAGE::SetState( PCM_PACKAGE_STATE aState )
void PANEL_PACKAGE::SetState( PCM_PACKAGE_STATE aState, bool aPinned )
{
m_data.state = aState;
m_data.pinned = aPinned;
m_splitButton->GetSplitButtonMenu()->Check( m_pinVersionMenuItem->GetId(), aPinned );
switch( aState )
{
@ -95,10 +102,15 @@ void PANEL_PACKAGE::SetState( PCM_PACKAGE_STATE aState )
m_button->Disable();
break;
case PCM_PACKAGE_STATE::PPS_INSTALLED:
m_splitButton->Hide();
m_button->Show();
m_button->SetLabel( _( "Uninstall" ) );
m_button->Enable();
m_button->Hide();
m_splitButton->Show();
m_splitButton->SetLabel( _( "Uninstall" ) );
m_splitButton->Bind( wxEVT_BUTTON, &PANEL_PACKAGE::OnButtonClicked, this );
m_actionMenuItem->SetItemLabel( _( "Update" ) );
m_splitButton->GetSplitButtonMenu()->Enable( m_actionMenuItem->GetId(), false );
break;
case PCM_PACKAGE_STATE::PPS_PENDING_INSTALL:
m_splitButton->Hide();
@ -113,9 +125,31 @@ void PANEL_PACKAGE::SetState( PCM_PACKAGE_STATE aState )
m_button->Disable();
break;
case PCM_PACKAGE_STATE::PPS_UPDATE_AVAILABLE:
// The only state where the split button is shown instead of the normal one
m_button->Hide();
m_splitButton->Show();
if( aPinned )
{
m_splitButton->SetLabel( _( "Uninstall" ) );
m_splitButton->Bind( wxEVT_BUTTON, &PANEL_PACKAGE::OnUninstallClick, this );
m_actionMenuItem->SetItemLabel( _( "Update" ) );
m_splitButton->GetSplitButtonMenu()->Enable( m_actionMenuItem->GetId(), true );
m_splitButton->GetSplitButtonMenu()->Bind( wxEVT_COMMAND_MENU_SELECTED,
&PANEL_PACKAGE::OnButtonClicked, this,
m_actionMenuItem->GetId() );
}
else
{
m_splitButton->SetLabel( _( "Update" ) );
m_splitButton->Bind( wxEVT_BUTTON, &PANEL_PACKAGE::OnButtonClicked, this );
m_actionMenuItem->SetItemLabel( _( "Uninstall" ) );
m_splitButton->GetSplitButtonMenu()->Enable( m_actionMenuItem->GetId(), true );
m_splitButton->GetSplitButtonMenu()->Bind( wxEVT_COMMAND_MENU_SELECTED,
&PANEL_PACKAGE::OnUninstallClick, this,
m_actionMenuItem->GetId() );
}
break;
case PCM_PACKAGE_STATE::PPS_PENDING_UPDATE:
m_splitButton->Hide();
@ -152,6 +186,14 @@ void PANEL_PACKAGE::OnButtonClicked( wxCommandEvent& event )
}
void PANEL_PACKAGE::OnPinVersionClick( wxCommandEvent& event )
{
m_data.pinned = event.IsChecked();
m_pinCallback( m_data.package.identifier, m_data.state, m_data.pinned );
}
void PANEL_PACKAGE::OnUninstallClick( wxCommandEvent& event )
{
if( m_data.state == PPS_UPDATE_AVAILABLE )

View File

@ -32,12 +32,14 @@ struct PACKAGE_VIEW_DATA
const PCM_PACKAGE package;
wxBitmap* bitmap;
PCM_PACKAGE_STATE state;
bool pinned;
wxString repository_id;
wxString repository_name;
wxString current_version;
wxString update_version;
PACKAGE_VIEW_DATA( const PCM_PACKAGE aPackage ) :
package( std::move( aPackage ) ), bitmap( nullptr ), state( PPS_INSTALLED ){};
package( std::move( aPackage ) ), bitmap( nullptr ), state( PPS_INSTALLED ),
pinned( false ){};
PACKAGE_VIEW_DATA( const PCM_INSTALLATION_ENTRY& aEntry ) :
package( std::move( aEntry.package ) ), bitmap( nullptr )
{
@ -45,6 +47,7 @@ struct PACKAGE_VIEW_DATA
repository_id = aEntry.repository_id;
repository_name = aEntry.repository_name;
current_version = aEntry.current_version;
pinned = aEntry.pinned;
}
};
@ -53,12 +56,15 @@ struct PACKAGE_VIEW_DATA
using ActionCallback = std::function<void( const PACKAGE_VIEW_DATA& aData,
PCM_PACKAGE_ACTION aAction, const wxString& aVersion )>;
using PinCallback = std::function<void( const wxString& aPackageId, const PCM_PACKAGE_STATE aState,
const bool aPinned )>;
class PANEL_PACKAGE : public PANEL_PACKAGE_BASE
{
public:
PANEL_PACKAGE( wxWindow* parent, const ActionCallback& aCallback,
const PACKAGE_VIEW_DATA& aData );
const PinCallback& aPinCallback, const PACKAGE_VIEW_DATA& aData );
///< Sets callback for OnClick action
void SetSelectCallback( const std::function<void()>& aCallback );
@ -69,13 +75,15 @@ public:
void OnButtonClicked( wxCommandEvent& event ) override;
///< Changes state of the (un)install button
void SetState( PCM_PACKAGE_STATE aState );
void SetState( PCM_PACKAGE_STATE aState, bool aPinned );
///< Called when anywhere on the panel is clicked (except install button)
void OnClick( wxMouseEvent& event ) override;
void OnUninstallClick( wxCommandEvent& event );
void OnPinVersionClick( wxCommandEvent& event );
void OnSize( wxSizeEvent& event ) override;
///< Get preferred version. If criteria are not met, return wxEmptyString
@ -87,9 +95,12 @@ private:
void OnPaint( wxPaintEvent& event ) override;
private:
wxMenuItem* m_pinVersionMenuItem;
wxMenuItem* m_actionMenuItem;
std::function<void()> m_selectCallback;
bool m_selected = false;
const ActionCallback& m_actionCallback;
const PinCallback& m_pinCallback;
PACKAGE_VIEW_DATA m_data;
int m_minHeight;
};

View File

@ -23,8 +23,8 @@
#include <html_window.h>
#include <pgm_base.h>
#include <settings/common_settings.h>
#include <settings/settings_manager.h>
#include <settings/kicad_settings.h>
#include <settings/settings_manager.h>
#include <string_utils.h>
#include <widgets/wx_panel.h>
#include <widgets/wx_splitter_window.h>
@ -49,9 +49,11 @@ std::unordered_map<PCM_PACKAGE_VERSION_STATUS, wxString> PANEL_PACKAGES_VIEW::ST
PANEL_PACKAGES_VIEW::PANEL_PACKAGES_VIEW( wxWindow* parent,
std::shared_ptr<PLUGIN_CONTENT_MANAGER> aPcm ) :
std::shared_ptr<PLUGIN_CONTENT_MANAGER> aPcm,
const ActionCallback& aActionCallback,
const PinCallback& aPinCallback ) :
PANEL_PACKAGES_VIEW_BASE( parent ),
m_pcm( aPcm )
m_pcm( aPcm ), m_actionCallback( aActionCallback ), m_pinCallback( aPinCallback )
{
// Replace wxFormBuilder's sash initializer with one which will respect m_initialSashPos.
m_splitter1->Disconnect( wxEVT_IDLE,
@ -121,17 +123,14 @@ void PANEL_PACKAGES_VIEW::ClearData()
}
void PANEL_PACKAGES_VIEW::SetData( const std::vector<PACKAGE_VIEW_DATA>& aPackageData,
ActionCallback aCallback )
void PANEL_PACKAGES_VIEW::SetData( const std::vector<PACKAGE_VIEW_DATA>& aPackageData )
{
m_actionCallback = aCallback;
ClearData();
for( const PACKAGE_VIEW_DATA& data : aPackageData )
{
PANEL_PACKAGE* package_panel =
new PANEL_PACKAGE( m_packageListWindow, m_actionCallback, data );
new PANEL_PACKAGE( m_packageListWindow, m_actionCallback, m_pinCallback, data );
package_panel->SetSelectCallback(
[package_panel, this]()
@ -149,7 +148,7 @@ void PANEL_PACKAGES_VIEW::SetData( const std::vector<PACKAGE_VIEW_DATA>& aPackag
m_packagePanels.insert( { data.package.identifier, package_panel } );
m_packageInitialOrder.push_back( data.package.identifier );
if( data.state == PPS_UPDATE_AVAILABLE )
if( data.state == PPS_UPDATE_AVAILABLE && !data.pinned )
m_updateablePackages.insert( data.package.identifier );
}
@ -429,13 +428,13 @@ bool PANEL_PACKAGES_VIEW::canRunAction() const
void PANEL_PACKAGES_VIEW::SetPackageState( const wxString& aPackageId,
const PCM_PACKAGE_STATE aState )
const PCM_PACKAGE_STATE aState, const bool aPinned )
{
auto it = m_packagePanels.find( aPackageId );
if( it != m_packagePanels.end() )
{
it->second->SetState( aState );
it->second->SetState( aState, aPinned );
if( m_currentSelected && m_currentSelected == it->second )
{
@ -443,7 +442,7 @@ void PANEL_PACKAGES_VIEW::SetPackageState( const wxString& aPackageId,
m_currentSelected->OnClick( dummy );
}
if( aState == PPS_UPDATE_AVAILABLE )
if( aState == PPS_UPDATE_AVAILABLE && !aPinned )
{
m_updateablePackages.insert( aPackageId );
}

View File

@ -35,24 +35,26 @@
class PANEL_PACKAGES_VIEW : public PANEL_PACKAGES_VIEW_BASE
{
public:
PANEL_PACKAGES_VIEW( wxWindow* parent, std::shared_ptr<PLUGIN_CONTENT_MANAGER> aPcm );
PANEL_PACKAGES_VIEW( wxWindow* parent, std::shared_ptr<PLUGIN_CONTENT_MANAGER> aPcm,
const ActionCallback& aCallback, const PinCallback& aPinCallback );
~PANEL_PACKAGES_VIEW();
/**
* @brief Recreates package panels and displays data
*
* @param aPackageData list of package view data
* @param aCallback (un)install button callback
*/
void SetData( const std::vector<PACKAGE_VIEW_DATA>& aPackageData, ActionCallback aCallback );
void SetData( const std::vector<PACKAGE_VIEW_DATA>& aPackageData );
/**
* @brief Set the state of package
*
* @param aPackageId id of the package
* @param aState new state
* @param aPinned indicates pinned version
*/
void SetPackageState( const wxString& aPackageId, const PCM_PACKAGE_STATE aState );
void SetPackageState( const wxString& aPackageId, const PCM_PACKAGE_STATE aState,
const bool aPinned );
///< Destroys package panels
void ClearData();
@ -115,7 +117,8 @@ private:
PCM_PACKAGE_ACTION getAction() const;
private:
ActionCallback m_actionCallback;
const ActionCallback& m_actionCallback;
const PinCallback& m_pinCallback;
std::unordered_map<wxString, PANEL_PACKAGE*> m_packagePanels;
std::vector<wxString> m_packageInitialOrder;
PANEL_PACKAGE* m_currentSelected;

View File

@ -813,7 +813,6 @@ PCM_PACKAGE_STATE PLUGIN_CONTENT_MANAGER::GetPackageState( const wxString& aRepo
try
{
repo = &getCachedRepository( aRepositoryId );
}
catch( ... )
{
@ -938,6 +937,24 @@ PLUGIN_CONTENT_MANAGER::GetInstalledPackageVersion( const wxString& aPackageId )
}
bool PLUGIN_CONTENT_MANAGER::IsPackagePinned( const wxString& aPackageId ) const
{
if( m_installed.find( aPackageId ) == m_installed.end() )
return false;
return m_installed.at( aPackageId ).pinned;
}
void PLUGIN_CONTENT_MANAGER::SetPinned( const wxString& aPackageId, const bool aPinned )
{
if( m_installed.find( aPackageId ) == m_installed.end() )
return;
m_installed.at( aPackageId ).pinned = aPinned;
}
int PLUGIN_CONTENT_MANAGER::GetPackageSearchRank( const PCM_PACKAGE& aPackage,
const wxString& aSearchTerm )
{
@ -1096,11 +1113,14 @@ void PLUGIN_CONTENT_MANAGER::RunBackgroundUpdate()
if( m_installed.size() == 0 )
return;
// Only fetch repositories that have installed packages
// Only fetch repositories that have installed not pinned packages
std::unordered_set<wxString> repo_ids;
for( auto& entry : m_installed )
repo_ids.insert( entry.second.repository_id );
{
if( !entry.second.pinned )
repo_ids.insert( entry.second.repository_id );
}
for( const auto& entry : m_repository_list )
{
@ -1132,7 +1152,7 @@ void PLUGIN_CONTENT_MANAGER::RunBackgroundUpdate()
GetPackageState( installed_package.repository_id,
installed_package.package.identifier );
if( state == PPS_UPDATE_AVAILABLE )
if( state == PPS_UPDATE_AVAILABLE && !installed_package.pinned )
availableUpdateCount++;
}

View File

@ -240,6 +240,25 @@ public:
*/
PCM_PACKAGE_STATE GetPackageState( const wxString& aRepositoryId, const wxString& aPackageId );
/**
* @brief Returns pinned status of a package
*
* @param aPackageId package id
* @return true if package is installed and is pinned
* @return false if package is not installed or not pinned
*/
bool IsPackagePinned( const wxString& aPackageId ) const;
/**
* @brief Set the pinned status of a package
*
* no-op for not installed packages
*
* @param aPackageId package id
* @param aPinned pinned status
*/
void SetPinned( const wxString& aPackageId, const bool aPinned );
/**
* @brief Get the preferred package update version or empty string if there is none
*

View File

@ -173,3 +173,28 @@ void from_json( const json& j, PCM_REPOSITORY& r )
to_optional( j, "manifests", r.manifests );
to_optional( j, "maintainer", r.maintainer );
}
void to_json( json& j, const PCM_INSTALLATION_ENTRY& e )
{
j = json{ { "package", e.package },
{ "current_version", e.current_version },
{ "repository_id", e.repository_id },
{ "repository_name", e.repository_name },
{ "install_timestamp", e.install_timestamp },
{ "pinned", e.pinned } };
}
void from_json( const json& j, PCM_INSTALLATION_ENTRY& e )
{
j.at( "package" ).get_to( e.package );
j.at( "current_version" ).get_to( e.current_version );
j.at( "repository_id" ).get_to( e.repository_id );
j.at( "repository_name" ).get_to( e.repository_name );
j.at( "install_timestamp" ).get_to( e.install_timestamp );
e.pinned = false;
if( j.contains( "pinned" ) )
j.at( "pinned" ).get_to( e.pinned );
}

View File

@ -23,9 +23,9 @@
#include "core/wx_stl_compat.h"
#include <optional>
#include <map>
#include <nlohmann/json.hpp>
#include <optional>
#include <string>
#include <tuple>
#include <vector>
@ -141,6 +141,7 @@ struct PCM_INSTALLATION_ENTRY
wxString repository_id;
wxString repository_name;
uint64_t install_timestamp;
bool pinned;
// Not serialized fields
bool update_available;
@ -203,8 +204,8 @@ void to_json( json& j, const PCM_REPOSITORY& r );
void from_json( const json& j, PCM_REPOSITORY& r );
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE( PCM_INSTALLATION_ENTRY, package, current_version, repository_id,
repository_name, install_timestamp );
void to_json( json& j, const PCM_INSTALLATION_ENTRY& e );
void from_json( const json& j, PCM_INSTALLATION_ENTRY& e );
#endif // PCM_DATA_H_