Editor/LibrarySystemWindow.cs

An editor window UI for the Library System, shown under Tools > Library System. It lists the project libraries and provides controls to view versions, install from sbox.game, publish and remove libraries by calling LibraryTools helper methods and LibrarySystem APIs.

File AccessNetworking
using Editor;
using Sandbox;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace LibraryTools;

/// <summary>
/// Library System as an editor window (Tools > Library System). Same actions as the MCP tools, which it
/// calls directly: list the project's libraries, check published versions, install, remove and publish.
/// </summary>
[EditorApp( "Library System", "library_books", "List, install, remove and publish the project's libraries" )]
public sealed class LibrarySystemWindow : Widget
{
	readonly Widget _list;
	readonly LineEdit _ident;
	readonly Label _output;

	public LibrarySystemWindow() : base( null )
	{
		WindowTitle = "Library System";
		SetWindowIcon( "library_books" );
		WindowFlags = WindowFlags.Dialog | WindowFlags.Customized | WindowFlags.WindowTitle | WindowFlags.CloseButton | WindowFlags.WindowSystemMenuHint;
		DeleteOnClose = true;
		MinimumSize = new Vector2( 620, 420 );

		Layout = Layout.Column();
		Layout.Margin = 12;
		Layout.Spacing = 8;

		Layout.Add( new Label.Subtitle( "Libraries in this project" ) );
		_list = Layout.Add( new Widget( this ) );
		_list.Layout = Layout.Column();
		_list.Layout.Spacing = 4;

		Layout.Add( new Label.Subtitle( "Install from sbox.game" ) );
		var row = Layout.AddRow();
		row.Spacing = 4;
		_ident = row.Add( new LineEdit( this ) { PlaceholderText = "org.package, e.g. rwtrcsc.lobbysystem" }, 1 );
		row.Add( new Button( "Versions", "history", this ) { Clicked = () => Run( "Versions", () => LibraryTools.LibraryVersions( Ident() ) ) } );
		row.Add( new Button.Primary( "Install", "download", this ) { Clicked = () => Run( "Install", async () => { var r = await LibraryTools.LibraryInstall( Ident() ); Refresh(); return r; } ) } );

		Layout.AddStretchCell();
		_output = Layout.Add( new Label( "Ready.", this ) { WordWrap = true, TextSelectable = true } );

		Refresh();
	}

	string Ident() => _ident.Value?.Trim() ?? "";

	void Refresh()
	{
		_list.Layout.Clear( true );
		var libs = LibrarySystem.All.ToList();
		if ( libs.Count == 0 ) _list.Layout.Add( new Label( "No libraries in Libraries/ yet.", _list ) );

		foreach ( var lib in libs )
		{
			var ident = (lib.Project?.Package?.FullIdent ?? "").Split( '#' )[0];
			var title = lib.Project?.Config?.Title ?? ident;
			var row = _list.Layout.AddRow();
			row.Spacing = 4;
			row.Add( new Label( $"{title}   {ident}   {(lib.Version?.ToString() ?? "local")}", _list ), 1 );
			row.Add( new Button( "Versions", "history", _list ) { Clicked = () => Run( $"Versions of {ident}", () => LibraryTools.LibraryVersions( ident ) ) } );
			row.Add( new Button( "Publish", "publish", _list )
			{
				Clicked = () => Dialog.AskString( change => Run( $"Publish {ident}", () => LibraryTools.LibraryPublish( ident, change ) ),
					$"Publish a new revision of {title}. Revision title:", "Publish", "Cancel", "", "Publish library" )
			} );
			row.Add( new Button( "Remove", "delete", _list )
			{
				Clicked = () => Dialog.AskConfirm( () => { _output.Text = LibraryTools.LibraryUninstall( ident ); Refresh(); },
					$"Remove {title} and delete its folder from Libraries/?", "Remove library", "Remove", "Cancel" )
			} );
		}
	}

	// Runs an action, showing progress and the result (or the error) in the output line.
	async void Run( string what, Func<Task<string>> action )
	{
		_output.Text = $"{what}...";
		try { _output.Text = await action(); }
		catch ( Exception e ) { _output.Text = $"{what} failed: {e.Message}"; }
	}
}