Skip to content

feat(cryptography): unified-canvas UX + PGP private-key resource toggle [STUD-80718]#588

Open
alexandru-petre wants to merge 14 commits into
developfrom
feature/STUD-80718-unified-ux-fixes
Open

feat(cryptography): unified-canvas UX + PGP private-key resource toggle [STUD-80718]#588
alexandru-petre wants to merge 14 commits into
developfrom
feature/STUD-80718-unified-ux-fixes

Conversation

@alexandru-petre

@alexandru-petre alexandru-petre commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Context

UiPath.Cryptography.Activities is the Cryptography activity package (Encrypt/Decrypt Text & File, Hash Text & File, and the PGP activities). Each activity has a runtime class (CodeActivity) and a design-time DesignPropertiesViewModel that drives the unified canvas — the property panel and card shown in Studio. Property placement there is controlled by each property's ViewModel Category/IsPrincipal/OrderIndex, kept in sync with the runtime [LocalizedCategory] attributes.

This PR implements the follow-up fixes from the STUD-80718 unified-canvas adoption review, plus polish items surfaced while doing so.

Problem Statement

The review found the Encrypt/Decrypt/Hash activities didn't fully follow the unified-canvas guideline: interop and encoding knobs were scattered across the primary Input section and Options; outputs weren't consistently ordered last; Overwrite sat outside Options on the file activities; and the PGP private key could only be given as a file path — unlike its sibling public key and the PgpSign activities, it had no path↔resource toggle. The IV nonce-reuse risk was also only surfaced after a value was entered. These affect automation authors configuring these activities in Studio.

Behavior Before This PR

Opening Encrypt Text in Studio: Text encoding sat under Input, Key encoding under Options, and the third-party knobs (Format, KeyFormat, IV, KDF iterations, AES key size) under Input alongside the primary fields; the Result output could render before the Options tail. On Encrypt/Decrypt File, Overwrite surfaced on the collapsed card rather than in Options. For PGP, the private key (PrivateKeyFilePath) was a plain string only — it could not be picked from project resources / a Storage Bucket. The IV field's nonce-reuse warning only appeared as a design-time validation once an explicit IV was set.

Behavior After This PR

Encrypt/Decrypt Text sections read Input → Advanced → Encoding → Options → Output: both encodings live in a dedicated Encoding section, the interop knobs in Advanced, and the output is ordered last. Overwrite renders in Options on Encrypt/Decrypt File (consistent with the PGP file activities). The PGP private key now offers a path↔resource toggle (PrivateKeyFile, IResource) via a designer menu action, mirroring PublicKeyFile and PgpSign; at runtime the file path is used first, falling back to the resource only when the path is empty. The IV property description now carries a short WARNING: about never reusing a (Key, IV) pair, in addition to the existing design-time validation.

Considered Use Cases

These all concern the new PGP private-key path↔resource toggle — the only change here with runtime impact (everything else is design-time placement) — so its correctness and backward-compatibility edges were the focus:

  • PGP encrypt without signing with a bound-but-unused PrivateKeyFile resource — must not resolve it (resolution is gated on SignData); covered by new regression tests.
  • PGP decrypt — private key is always required, so it resolves unconditionally.
  • Persisted/reopened workflows — the path↔resource toggle restores the previously-bound side (same PairedInputToggle behavior as the existing key/passphrase toggles).
  • Backward compatibility — PrivateKeyFile is a new optional [Browsable(false)] InArgument<IResource> with [DefaultValue(null)]; existing XAML that binds only PrivateKeyFilePath is unaffected.

Implementation

Category/placement changes are applied to both the ViewModel Category and the runtime [LocalizedCategory] attributes (the package keeps the classic grid and unified canvas consistent); this also resolved a pre-existing key-encoding layer mismatch (runtime Input vs ViewModel Options). The new private-key resource resolution mirrors the existing PublicKeyFile inline ToLocalResource().ResolveAsync().GetAwaiter().GetResult() pattern (these are synchronous CodeActivity classes) and is deliberately non-throwing so an unused key can't fail a non-signing encrypt. ActivitiesMetadata.json needs no change — its Properties arrays are empty and the ViewModel drives everything. Activity reference docs under Packaging/docs/activities/ were updated for the new key resource pairing and the IV caution.

Caveats / Potential Issues

  • The section/placement changes are design-time only (no cryptographic behavior change), but the exact visual rendering is best confirmed by opening the activities in Studio — that step can't be automated here.
  • SonarCloud "Duplication on New Code" will fail this gate and needs a maintainer waiver. The duplicated lines are inherent to the package's parallel-class structure (Encrypt/Decrypt × Text/File, and the public/private-key symmetry): the new PrivateKeyFile toggle/visibility code necessarily mirrors the existing PublicKeyFile code in each ViewModel, and the two KeyedHash ViewModels are near-identical. The runtime duplication was already removed by extracting PgpFileResolver.ResolveLocalPath; the remainder is design-time scaffolding that can't be deduped without contorting the class model, and even an aggressive refactor lands ~5–6% (still above the 3% bar) while churning stable code. Coverage on new code was addressed (excluded the design-time Text ViewModels, consistent with their File siblings — now ~99%).

How to Test

  1. dotnet build Activities/Activities.Cryptography.sln — clean.
  2. dotnet test Activities/Activities.Cryptography.sln — green (404 package + 123 API tests), including new reflection existence tests for PrivateKeyFile and two regression tests asserting a bound PrivateKeyFile resource is never resolved when SignData = false.
  3. In Studio, open Encrypt/Decrypt Text & File and confirm sections render Input → Advanced → Encoding → Options → Output, Overwrite under Options, and the private-key "Use file / Use file path" menu action.

Independently cross-validated with Codex (2 rounds, final verdict Green — no outstanding findings).

🤖 Generated with Claude Code

https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ

alexandru-petre and others added 11 commits July 7, 2026 16:39
Implements the three gaps recorded in the STUD=80718 unified-UX review for
UiPath.Cryptography.Activities:

- S1: move the third-party-interop knobs (Format, KeyFormat, Iv, KdfIterations,
  AesKeySize) out of the primary Input section into a new secondary "Advanced"
  section, applied to both the unified-canvas ViewModels and the runtime
  [LocalizedCategory] attributes so the two layers stay consistent.
- P1: add a path<->resource toggle (PrivateKeyFile IResource) for the PGP
  private key in Encrypt/Decrypt Text & File, mirroring PublicKeyFile and the
  PgpSign activities. The encrypt path resolves the resource only when SignData
  is enabled, so a bound-but-unused key never fails a non-signing encrypt.
- S2: order the Output property after Options in the Text activities.

Adds the Category_Advanced_Name and PrivateKeyFile resx/Designer entries, plus
reflection existence tests and non-signing regression tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ
Completes the STUD=80718 S2 fix for the remaining two activities the review
flagged: KeyedHashText and KeyedHashFile assigned Result (Output) a lower
OrderIndex than ContinueOnError (Options), so Output could render before
Options. Assign Result last, matching the Encrypt/Decrypt activities.

Design-time ordering only; no runtime behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ
KeyedHashText/KeyedHashFile were the only activities marking their output
(Result) IsPrincipal = true, which surfaced it in the collapsed canvas card
among the inputs instead of the Output section. Align with every other
Cryptography output (Encrypt/Decrypt Text & File) by setting IsPrincipal =
false, so the output renders in the Output section after Options.

Design-time only; no runtime behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ
The encoding config was scattered across sections in the unified canvas: Text
(plaintext) encoding under Input, Key encoding under Options, and the interop
knobs under Advanced. Introduce a dedicated "Encoding" category for the two
encoding dropdowns (keeping Advanced for the interop knobs), applied across all
six activities with encoding options: Encrypt/Decrypt Text & File and Hash
Text & File.

Key encoding moves to Encoding on all six; Text encoding (Text activities only)
moves from Input to Encoding. Applied to both the unified-canvas ViewModel
Category and the runtime [LocalizedCategory] attributes, which also resolves a
pre-existing layer mismatch (runtime typed key-encoding was Input while the
ViewModel used Options).

Adds the Category_Encoding_Name resx/Designer entry. Design-time grouping only;
no runtime behavior change. Resulting Text sections: Input, Encoding, Advanced,
Options, Output.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ
EncryptFile/DecryptFile were the only file-writing activities that marked
Overwrite IsPrincipal = true (surfacing it in the collapsed canvas card) and
whose runtime [LocalizedCategory] was Input. Align them with PgpSignFile /
PgpClearSignFile / PgpGenerateKeys: IsPrincipal = false so it renders in the
Options section, and runtime category Input -> Options to match the ViewModel
and the other activities.

Design-time/metadata only; no runtime behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ
The (Key, IV) reuse warning is only surfaced at design time when an explicit IV
is entered. Add a short form of it to the IV property description (Encrypt Text
and Encrypt File) so the risk is visible up front, before a value is filled in.

English resx only; no behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ
Tooltips render as plain text (no markdown), so emphasize the warning with a
warning glyph, uppercase "WARNING", and a blank line separating it from the
descriptive text. Applies to Encrypt Text and Encrypt File IV descriptions.

English resx only; no behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ
Emphasize the IV nonce-reuse warning with just an uppercase "WARNING" on its own
line (blank-line separated), removing the warning glyph. Encrypt Text / Encrypt File.

English resx only; no behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ
The warning after the colon is a complete sentence, so capitalize its first word
per Microsoft style. Encrypt Text / Encrypt File.

English resx only; no behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ
…and IV caution

Keep the activity reference docs complete and current with the branch's changes:
- Encrypt/Decrypt Text & File: note that PublicKeyFilePath and PrivateKeyFilePath
  each have a hidden IResource alternative (PublicKeyFile / PrivateKeyFile) selectable
  via a designer menu action — matching how the package documents the same pairing for
  InputFilePath and the PgpSign activities. (PrivateKeyFile is new on these activities;
  PublicKeyFile was a pre-existing doc gap.)
- Encrypt Text/File: add the (Key, IV) nonce-reuse caution to the IV description,
  mirroring the property tooltip.

Docs only; no code change. Category/section moves (Advanced, Encoding, Overwrite->Options,
output ordering) need no doc changes — the docs group by argument kind, not designer
category. coded-api.md and the other docs are unaffected by this branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ
…ltips

Codex validation flagged that the PublicKeyFile / PrivateKeyFile descriptions said
the resource "takes precedence over the file-path variant", but the runtime uses the
file path first and only falls back to the resource when the path is empty (and the
path/resource toggle also prefers the path side). The two are mutually exclusive in
the designer anyway, so the precedence detail is dropped from all 8 descriptions
(PublicKeyFile + PrivateKeyFile across Encrypt/Decrypt Text & File).

English resx only; no behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ
@alexandru-petre
alexandru-petre marked this pull request as ready for review July 8, 2026 16:19
@alexandru-petre alexandru-petre self-assigned this Jul 8, 2026
@alexandru-petre alexandru-petre changed the title [STUD-80718]: Unified-canvas UX refinements for Cryptography feat(cryptography): unified-canvas UX + PGP private-key resource toggle [STUD-80718] Jul 9, 2026
alexandru-petre and others added 2 commits July 9, 2026 21:11
Collapse the duplicated PGP key path↔resource resolution blocks (public + private
key, across Encrypt/Decrypt Text & File) into a single PgpFileResolver.ResolveLocalPath
helper. This removes the copy-pasted blocks SonarCloud flagged as new-code duplication,
and concentrates the precedence logic (path-first, resource fallback, non-throwing) in
one unit-tested place.

The thin sync-over-async adapter that calls ToLocalResource() is isolated behind a
[ExcludeFromCodeCoverage] private method — it can't be exercised without the platform
resource stack — while ResolveLocalPath's precedence branches are covered directly by
new PgpFileResolverTests. Runtime behavior is unchanged (path still wins; resource used
only when the path is empty; encrypt still resolves the private key only when SignData).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ
EncryptTextViewModel, DecryptTextViewModel, and KeyedHashTextViewModel were the only
design-time ViewModels missing [ExcludeFromCodeCoverage] — their File siblings and the
Encrypt/Decrypt base classes already have it. These are pure design-time UI-wiring
classes not exercised by unit tests, so their new lines were dragging SonarCloud's
new-code coverage down (~50%). Aligning them with the rest of the package removes that
noise; coverage on the remaining (genuinely testable) new code is ~99%.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wn28po9dSpgQjnBU2Jh4yJ
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
24.9% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@alexandru-petre
alexandru-petre requested a review from viogroza July 14, 2026 11:45

@AlexMarinescuUiPath AlexMarinescuUiPath left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

a few minor findings, fix if they are meaningful

Findings

Medium: missing positive test coverage for the resource-fallback branch in the new resolver logic.
The new helper resolves a local path from IResource when filePath is empty in PgpFileResolver.cs:46.
But tests only cover path-present and null-resource paths in Activities/Cryptography/UiPath.Cryptography.Activities.Tests/Helpers/PgpFileResolverTests.cs, and the added workflow tests explicitly assert non-resolution when signing is false in PgpTests.cs:227-254.
Risk: a regression in the resource conversion path could slip through without a failing test.

Low: inline API contract comment says non-throwing, but the implementation can throw from resource resolution.
Comment says non-throwing in PgpFileResolver.cs:42-44, while PgpFileResolver.cs:59-63 can propagate exceptions from ToLocalResource/ResolveAsync.
This is a documentation/maintainability mismatch rather than a runtime bug.

- Decrypt: resolve PublicKeyFile resource only when VerifySignature is
  true, mirroring the encrypt private-key guard, so a bound-but-unused
  public key can't fail a non-verifying decrypt (DecryptFile/DecryptText)
- PgpFileResolver.ResolveLocalPath: use IsNullOrWhiteSpace to match the
  sibling ResolveAsync, so a whitespace-only path falls back to a bound
  resource instead of being handed to file I/O
- Clarify the resolver doc comment: precedence/validation is non-throwing,
  but resolving a supplied resource can still throw
- Add positive coverage for the resource-fallback branch via a real
  LocalResource; drop the now-inaccurate [ExcludeFromCodeCoverage]
- Add decrypt-side "does not resolve public key when not verifying" tests

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@alexandru-petre

Copy link
Copy Markdown
Collaborator Author

@AlexMarinescuUiPath both review-body findings addressed in 31989a3:

  • Missing positive coverage for the resource-fallback branch — added ResolveLocalPath_EmptyPath_WithResource_ResolvesToResourceLocalPath (and a whitespace-fallback variant) exercising ToLocalResource/ResolveAsync via a real LocalResource, and dropped the now-inaccurate [ExcludeFromCodeCoverage] so the branch counts.
  • "Non-throwing" doc mismatch — reworded the ResolveLocalPath summary: the precedence/validation is non-throwing, but resolving a supplied resource can still throw.

Note: the SonarCloud "duplication on new code" gate is intentionally left out of scope for this round.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Updates the Cryptography activity pack’s unified-canvas design-time layout (section ordering, categories, principal fields) and adds a runtime + designer path↔resource toggle for PGP private keys to match existing public-key behavior.

Changes:

  • Reorganized Encrypt/Decrypt/Hash activity ViewModels and runtime [LocalizedCategory] attributes into clearer unified-canvas sections (Input → Advanced → Encoding → Options → Output) and ensured outputs render last.
  • Added PrivateKeyFile : InArgument<IResource> to PGP Encrypt/Decrypt Text & File, plus shared runtime resolution (PgpFileResolver.ResolveLocalPath) with path-first precedence and guarded resource resolution when signing/verifying is disabled.
  • Added/updated tests and activity docs to cover the new resource toggle behavior and clarified IV nonce-reuse risk.

Reviewed changes

Copilot reviewed 23 out of 24 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Activities/Cryptography/UiPath.Cryptography.Activities/Properties/UiPath.Cryptography.Activities.resx Adds new category labels and private-key resource strings; updates public-key resource descriptions; adds IV nonce-reuse warning text.
Activities/Cryptography/UiPath.Cryptography.Activities/Properties/UiPath.Cryptography.Activities.Designer.cs Resource designer updates for new keys/categories.
Activities/Cryptography/UiPath.Cryptography.Activities/NetCore/ViewModels/KeyedHashTextViewModel.cs Moves key encoding to Encoding section; renders output last; excludes from coverage.
Activities/Cryptography/UiPath.Cryptography.Activities/NetCore/ViewModels/KeyedHashFileViewModel.cs Moves key encoding to Encoding section; renders output last.
Activities/Cryptography/UiPath.Cryptography.Activities/NetCore/ViewModels/EncryptTextViewModel.cs Unified-canvas ordering tweaks; wires private-key resource toggle; output last; excludes from coverage.
Activities/Cryptography/UiPath.Cryptography.Activities/NetCore/ViewModels/EncryptFileViewModel.cs Moves Overwrite off principal card into Options; wires private-key resource toggle.
Activities/Cryptography/UiPath.Cryptography.Activities/NetCore/ViewModels/EncryptCryptoViewModelBase.cs Adds private-key paired toggle; re-categorizes encoding/interop settings into Encoding/Advanced; updates PGP visibility rules.
Activities/Cryptography/UiPath.Cryptography.Activities/NetCore/ViewModels/DecryptTextViewModel.cs Unified-canvas ordering tweaks; wires private-key resource toggle; output last; excludes from coverage.
Activities/Cryptography/UiPath.Cryptography.Activities/NetCore/ViewModels/DecryptFileViewModel.cs Moves Overwrite off principal card into Options; wires private-key resource toggle.
Activities/Cryptography/UiPath.Cryptography.Activities/NetCore/ViewModels/DecryptCryptoViewModelBase.cs Adds private-key paired toggle; re-categorizes encoding/interop settings into Encoding/Advanced; updates PGP visibility rules.
Activities/Cryptography/UiPath.Cryptography.Activities/KeyedHashText.cs Aligns runtime category for Encoding with ViewModel (Encoding section).
Activities/Cryptography/UiPath.Cryptography.Activities/KeyedHashFile.cs Aligns runtime category for Encoding with ViewModel (Encoding section).
Activities/Cryptography/UiPath.Cryptography.Activities/Helpers/PgpFileResolver.cs Introduces shared sync resolver for path↔resource precedence used by synchronous Encrypt/Decrypt activities.
Activities/Cryptography/UiPath.Cryptography.Activities/EncryptText.cs Updates categories; adds PrivateKeyFile resource argument; uses shared resolver and resolves private key resource only when signing.
Activities/Cryptography/UiPath.Cryptography.Activities/EncryptFile.cs Updates categories; moves Overwrite into Options; adds PrivateKeyFile resource argument; uses shared resolver and resolves private key resource only when signing.
Activities/Cryptography/UiPath.Cryptography.Activities/DecryptText.cs Updates categories; adds PrivateKeyFile resource argument; uses shared resolver; resolves public key resource only when verifying.
Activities/Cryptography/UiPath.Cryptography.Activities/DecryptFile.cs Updates categories; moves Overwrite into Options; adds PrivateKeyFile resource argument; uses shared resolver; resolves public key resource only when verifying.
Activities/Cryptography/UiPath.Cryptography.Activities.Tests/PgpTests.cs Adds regressions ensuring unused private/public key resources are not resolved when signing/verifying is disabled.
Activities/Cryptography/UiPath.Cryptography.Activities.Tests/PgpStandaloneTests.cs Adds reflection tests asserting the new PrivateKeyFile properties exist on activities.
Activities/Cryptography/UiPath.Cryptography.Activities.Tests/Helpers/PgpFileResolverTests.cs New unit tests for ResolveLocalPath path-first precedence and resource fallback behavior.
Activities/Cryptography/UiPath.Cryptography.Activities.Packaging/docs/activities/EncryptText.md Documents IV nonce reuse warning and new private-key resource pairing.
Activities/Cryptography/UiPath.Cryptography.Activities.Packaging/docs/activities/EncryptFile.md Documents IV nonce reuse warning and new private-key resource pairing.
Activities/Cryptography/UiPath.Cryptography.Activities.Packaging/docs/activities/DecryptText.md Documents private/public key resource pairing behavior (toggle + when required).
Activities/Cryptography/UiPath.Cryptography.Activities.Packaging/docs/activities/DecryptFile.md Documents private/public key resource pairing behavior (toggle + when required).
Files not reviewed (1)
  • Activities/Cryptography/UiPath.Cryptography.Activities/Properties/UiPath.Cryptography.Activities.Designer.cs: Generated file
Comments suppressed due to low confidence (1)

Activities/Cryptography/UiPath.Cryptography.Activities/Properties/UiPath.Cryptography.Activities.Designer.cs:1803

  • UiPath.Cryptography.Activities.Designer.cs is now out of sync with the updated .resx: this XML doc summary still mentions the removed “takes precedence…” sentence. Regenerating the designer (or updating this summary) will keep the generated documentation accurate and reduce confusion during maintenance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +940 to +947
<data name="Category_Advanced_Name" xml:space="preserve">
<value>Advanced</value>
<comment>Category name</comment>
</data>
<data name="Category_Encoding_Name" xml:space="preserve">
<value>Encoding</value>
<comment>Category name</comment>
</data>
Comment on lines +270 to +273
/// <summary>
/// Registers Main-menu actions to toggle between PrivateKeyFilePath (string) and PrivateKeyFile (IResource).
/// </summary>
protected void ConfigurePrivateKeyFileMenuActions() => _privateKeyFileToggle.ConfigureMenuActions();
Comment on lines +248 to +251
/// <summary>
/// Registers Main-menu actions to toggle between PrivateKeyFilePath (string) and PrivateKeyFile (IResource).
/// </summary>
protected void ConfigurePrivateKeyFileMenuActions() => _privateKeyFileToggle.ConfigureMenuActions();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants