Skip to content

Implement tool request form and notification system#22259

Draft
arash77 wants to merge 29 commits intogalaxyproject:devfrom
arash77:feature/tool-request-form
Draft

Implement tool request form and notification system#22259
arash77 wants to merge 29 commits intogalaxyproject:devfrom
arash77:feature/tool-request-form

Conversation

@arash77
Copy link
Copy Markdown
Member

@arash77 arash77 commented Mar 25, 2026

Closes #21758

Summary

Adds a Tool Request Form that allows logged-in users to request new tools to be installed on a Galaxy instance. Submitted requests are delivered to all admin users via Galaxy's existing notification system.

This PR also extends the feature to handle workflow runs with missing tools: when a workflow cannot be run because required Tool Shed tools are not installed, a one-click "Request Installation" button appears inline on the workflow run page so users can notify admins without filling out the full form.


Feature 1 — Tool Request Form (ToolBox panel)

User Flow

  1. A "Request a Tool" button appears in the ToolBox panel (left sidebar) for all logged-in, non-anonymous users when enable_tool_request_form: true is set in the Galaxy config. The button is only shown when a tool search returns no results.
  2. Clicking the button opens a modal form where the user fills in details about the tool they want installed.
  3. On submission, the backend sends a notification to every admin user via Galaxy's notification system (180-day expiration). The submitting user sees an inline success message.
tool-request-button tool-request-form-modal tool-request-form-bottom tool-request-done

Form Fields

Tool Information (required fields marked *):

  • Tool Name *
  • Homepage / Repository URL
  • Description *
  • Scientific Domain
  • Requested Version
  • Conda package available? (Yes / No / Unknown)
  • Test data available? (Yes / No / Unknown)

Requester Information:

  • Affiliation / Lab

Requester name and email are populated automatically from the authenticated user's account — they are not editable in the form to prevent spoofing.

The Submit Request button is disabled until both required fields (Tool Name, Description) are filled.


Feature 2 — Workflow Missing-Tools Install Request

User Flow

  1. A user opens a workflow run page. If one or more required tools are not installed, Galaxy normally shows an error message.
  2. With this feature enabled, that error alert also includes a "Request Installation (N missing tools)" button.
  3. Clicking it opens a confirmation dialog that names the workflow and the number of missing tools.
  4. On confirm, the same POST /api/tool_request_form endpoint is called with the full list of missing tool IDs and the workflow name. All admins are notified.
  5. After a successful request, the button is replaced by a success message. The result is stored in localStorage (keyed on the sorted tool IDs) so the button stays suppressed across page reloads — preventing duplicate requests.
  6. The button is hidden for anonymous users, when the feature flag is off, or if no tool IDs are available.
wf-missing-tools-button wf-missing-tools-dialog wf-missing-tools-success

Admin Side — Notification Inbox

When a tool request is submitted, all admin users receive a notification in their Galaxy notification inbox. Each notification shows the tool name, description, URL (if provided), and the requester's account name and email — populated automatically from their authenticated session.

admin-notifications-page

Architecture additions

Layer File Change
Backend error lib/galaxy/managers/workflows.py MessageException now includes missing_tool_ids in extra_error_info so the list is serialised into the JSON error response
Notification schema lib/galaxy/schema/notifications.py tool_ids and workflow_name added to ToolRequestNotificationContent
Backend service lib/galaxy/webapps/galaxy/services/tool_request_form.py tool_ids and workflow_name added to ToolRequestFormData and wired through to the notification
Frontend error class client/src/components/Workflow/Run/services.js WorkflowMissingToolsError (extends Error, carries missingToolIds[]); getRunData() throws it before rethrowSimple() can strip the structured data
Frontend component client/src/components/Workflow/Run/WorkflowMissingToolsRequest.vue New — button + confirmation dialog + localStorage deduplication
Frontend integration client/src/components/Workflow/Run/WorkflowRun.vue Catches WorkflowMissingToolsError, populates missingToolIds, renders WorkflowMissingToolsRequest; calls getWorkflowInfo() as a fallback on both standard and instance code paths to ensure the workflow name is available
TypeScript types client/src/api/schema/schema.ts tool_ids and workflow_name added to ToolRequestFormData
Integration test test/integration/test_tool_request_form.py test_workflow_install_request_with_tool_ids — submits with tool_ids + workflow_name, verifies both fields appear in the admin notification
Component tests client/src/components/Workflow/Run/WorkflowMissingToolsRequest.test.ts 25-test suite

Full Architecture

Layer File Role
Frontend button (ToolBox) client/src/components/Panels/ToolBox.vue Shows button when config.enable_tool_request_form && !isAnonymous and search has no results
Frontend form client/src/components/Tool/ToolRequestForm.vue Modal form, validation, success/error state
Frontend API client/src/api/toolRequestForm.ts Typed POST /api/tool_request_form call
Backend router lib/galaxy/webapps/galaxy/api/tool_request_form.py FastAPI endpoint (204 No Content)
Backend service lib/galaxy/webapps/galaxy/services/tool_request_form.py Validates config/auth, sends notification to all admins
Notification schema lib/galaxy/schema/notifications.py ToolRequestNotificationContent in notification union
Config lib/galaxy/config/schemas/config_schema.yml enable_tool_request_form (default: false)

The feature requires both enable_tool_request_form: true and enable_notification_system: true in galaxy.yml.


How to test the changes?

  • I've included appropriate automated tests.

  • This is a refactoring of components with existing test coverage.

  • Instructions for manual testing are as follows:

    Tool Request Form (ToolBox):

    1. Add to config/galaxy.yml:
      enable_tool_request_form: true
      enable_notification_system: true
    2. Start Galaxy and log in as a non-admin user.
    3. Search for a tool that doesn't exist — the "Request a Tool" button appears once the search returns no results.
    4. Fill in at least Tool Name and Description, then click Submit Request.
    5. Log in as an admin user and check the notification bell — a new tool request notification should appear, attributed to your account name and email automatically.

    Workflow Missing-Tools Button:

    1. Same config as above.
    2. Log in as a non-admin user and open the run page for a workflow that references tools not installed on the instance.
    3. The error alert should include a "Request Installation (N missing tools)" button.
    4. Click it, confirm in the dialog — the button is replaced by a success message and the admins are notified.
    5. Reload the page — the button remains suppressed (localStorage deduplication).

License

  • I agree to license these and all my past contributions to the core galaxy codebase under the MIT license.

@arash77 arash77 changed the title Implement tool request form and notification system [WIP] Implement tool request form and notification system Mar 25, 2026
@arash77 arash77 force-pushed the feature/tool-request-form branch 2 times, most recently from c0b39cc to db2f14a Compare April 15, 2026 12:06
@arash77 arash77 marked this pull request as ready for review April 15, 2026 13:07
@arash77 arash77 changed the title [WIP] Implement tool request form and notification system Implement tool request form and notification system Apr 15, 2026
@github-actions github-actions Bot added this to the 26.1 milestone Apr 15, 2026
Copy link
Copy Markdown
Contributor

@davelopez davelopez left a comment

Choose a reason for hiding this comment

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

Looking pretty solid already!

Some comments for potential improvements below.

Comment thread client/src/api/notifications.ts Outdated
Comment thread client/src/components/BaseComponents/GModal.vue
async function mountForm(show = true): Promise<Wrapper<Vue>> {
// Suppress FormBoolean null-value prop warnings — condaAvailable and testDataAvailable
// are intentionally null until the user interacts with them.
vi.spyOn(console, "error").mockImplementation(() => {});
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.

We should not silence all console errors; there are some helpers to do that in client/tests/vitest/helpers.js

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Switched to suppressExpectedErrorMessages from @tests/vitest/helpers (ToolRequestForm.test.ts:4,23), scoped to the expected "Invalid prop: type check failed for prop" pattern only.

<h6 v-localize class="font-weight-bold mb-2">Tool Information</h6>

<BFormGroup label="Tool Name *" label-for="tool-request-name">
<BFormInput
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.

Instead of bootstrap inputs, you can use Galaxy's FormElement. It should give you more consistent forms UI with the rest of Galaxy.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Replaced bootstrap inputs with <FormElement> in f4db42d (ToolRequestForm.vue:9,133-177). Only BAlert for success/error banners remains.

`,
new_shared_item:
"You will receive these notifications when someone shares an item with you i.e. a history, workflow, visualization, etc.",
tool_request:
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.

Hmmm, interesting... this will not make sense for normal users, only for admins. And if admins opt out of this kind of notification, then it will defeat the purpose... so probably better drop the setting from the UI.

Copy link
Copy Markdown
Member Author

@arash77 arash77 May 4, 2026

Choose a reason for hiding this comment

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

Cleaned this up in b4fe427: tool_request is filtered out of user-facing categories, and the stale tool_request entry was removed from categoryDescriptionMap.

<template v-if="props.notification.content.tool_url">
<dt>URL</dt>
<dd>
<BLink :href="props.notification.content.tool_url" target="_blank">
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.

I will not render this as a link to avoid accidentally clicking it in case of a "malicious" user trying to do some kind of Admin-targeted URL injection.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hardened in 721e3c9 + c3a4006. URL renders as plain text inside <span class="text-break"> (NotificationCard.vue:210-215); no anchor.

try {
await submitToolRequest({
tool_name: toolName.value.trim(),
tool_url: toolUrl.value.trim() || undefined,
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.

Not sure if you want to do any more validation for the URL here; there should be some utils for that. Like ignoring non-https links, etc.

Copy link
Copy Markdown
Member Author

@arash77 arash77 May 4, 2026

Choose a reason for hiding this comment

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

Updated in b4fe427: ToolRequestForm.vue now uses the shared isValidNetworkUrl utility from @/utils/url, composed with the local https:// requirement. I kept the HTTPS-only policy here because url.ts’s broader validateUrl() accepts upload-flow schemes like ftp:///gxfiles://.

desc: |
Enable the integration of the Galaxy Help Forum in the tool panel. This requires the help_forum_api_url to be set.

enable_tool_request_form:
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.

When you add a new config option, you should run make config-rebuild.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done in d47de6d (galaxy.yml.sample:3225 now contains #enable_tool_request_form: false).


message = "message"
new_shared_item = "new_shared_item"
tool_request = "tool_request"
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.

This new category does not have email "wiring". Have a look at email_templates_by_category and lib/galaxy/config/templates/mail/notifications/

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Wired in bc38745. lib/galaxy/managers/notification.py:860 maps PersonalNotificationCategory.tool_request → ToolRequestEmailNotificationTemplateBuilder in email_templates_by_category. Templates added: lib/galaxy/config/templates/mail/notifications/tool_request-email.{html,txt}.

Comment on lines +74 to +75
requester_name: requesterName.value.trim(),
requester_email: requesterEmail.value.trim() || undefined,
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.

Thinking about this, probably the user details should be filled out by the server to avoid any spoofing attempts.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done in 2d41858 + 66a09d8. Form no longer collects requester fields (ToolRequestForm.vue:19-24); server fills requester_email from the authenticated user. Test asserts payload omits requester_email/requester_name (ToolRequestForm.test.ts:113,115).

Copy link
Copy Markdown
Member

@mvdbeek mvdbeek left a comment

Choose a reason for hiding this comment

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

I like most of it, but it'd be awesome if you can use the notifications API instead of a bespoke API for this.

Comment thread client/src/api/schema/schema.ts Outdated
patch?: never;
trace?: never;
};
"/api/tool_request_form": {
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.

Can we please use an existing route (or make a generic one) for that ? We don't want a new endpoint for every type of message we could add.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done in e18329a. Submission now POST /api/notifications (client/src/api/notifications.ts:74); dedicated tool-request endpoint removed.

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.

Currently, only admins can POST new notifications (to avoid any potential spam), but maybe you can add a filter to allow certain "categories" of notifications, starting with this one :)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This has already been done: non-admin submissions now go through POST /api/notifications and are limited by a server-side allow-list, currently only tool_request.

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.

True! Sorry for the noise!

Comment thread client/src/api/schema/schema.ts Outdated
*/
ToolRequestFormData: {
/**
* Conda available
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.

That doesn't seem like something a user would know, and even if they did we can't trust that so it's just more work, and even if there is a package it doesn't help if it's in some random channel.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Removed in 3f22971f9. No conda_available field anywhere in the current schema; test asserts absent (ToolRequestForm.test.ts:117).

Comment thread client/src/api/schema/schema.ts Outdated
* Requester affiliation
* @description The affiliation/lab of the requester.
*/
requester_affiliation?: string | null;
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'd just add an additional remarks field here. If they use OIDC or institutional email we can get that from their user profile.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Replaced with additional_remarks (notifications.py:147, notifications.ts:41,67). requester_email is derived server-side from the authenticated user's profile.

Comment thread client/src/api/schema/schema.ts Outdated
* Test data available
* @description Whether test data for this tool is available.
*/
test_data_available?: boolean | null;
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.

Let's not do that, same reason as the conda check

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Removed in 3f22971f9. No test_data_available field; test asserts absent (ToolRequestForm.test.ts:118).

Comment thread client/src/api/schema/schema.ts Outdated
* Tool name
* @description The name of the requested tool.
*/
tool_name: string;
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.

This is a string, but tool ids is an array, so that doesn't line up

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Now tool_names: list[str] with min_length=1 (notifications.py:122-124); form sends array [toolName.value.trim()] (ToolRequestForm.vue:86); TypeScript type tool_names: string[] (notifications.ts:34,61).

Comment thread client/src/api/schema/schema.ts Outdated
* Workflow name
* @description Name of the workflow requiring these tools, if applicable.
*/
workflow_name?: string | null;
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.

A workflow id that we should have in the context is probably more useful ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done in 252a8d2. WorkflowMissingToolsRequest.vue:13-16 takes workflowId as a prop and submits it as workflow_id at line 48 (schema field notifications.py:144).

</BAlert>

<BAlert v-if="submitted || alreadyRequested" variant="success" show>
Installation request sent — admins have been notified and will review it shortly.
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.

Don't the notifications have an ID ? Seems like we could link to the actual notification message

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

submitUserNotification now returns the encoded notification id (notifications.ts:73-93); the component captures it (WorkflowMissingToolsRequest.vue:46,52) and renders a link: <BLink :href="/user/notifications#notification-card-${submittedNotificationId}">view your request</BLink> (line 70). The anchor target is the id on each card (NotificationCard.vue:157).

<BAlert v-if="workflowError" variant="danger" show>
<h2 class="h-text">Workflow cannot be executed. Please resolve the following issue:</h2>
{{ workflowError }}
<WorkflowMissingToolsRequest :missing-tool-ids="missingToolIds" :workflow-name="workflowName" />
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.

Doesn't that need to be guarded by whether the feature is enabled ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes — <WorkflowMissingToolsRequest v-if="config?.enable_tool_request_form" ...> (WorkflowRun.vue:242-243). The component itself double-guards (WorkflowMissingToolsRequest.vue:26-32): isConfigLoaded && config.enable_tool_request_form && !userStore.isAnonymous.

@arash77 arash77 moved this from Needs Review to In Progress in Galaxy Dev - weeklies Apr 21, 2026
@davelopez davelopez marked this pull request as draft April 22, 2026 12:23
arash77 added 15 commits May 4, 2026 11:17
…l watch

- ToolBox.vue: change v-model:show to :show.sync (Vue 2 syntax), remove
  template ref since modal is controlled reactively via show prop
- ToolRequestForm.vue: remove redundant watch/ref/expose since GModal
  already handles show/hide via its own watchImmediate on the show prop
- ToolRequestForm.test.ts: replace dialog.open DOM assertion with
  GModal props check for environment-agnostic testing
…olean fields

FormBoolean requires Boolean|String prop and warns on null, causing
ToolPanel and ToolBoxSearch tests to fail via vitest-fail-on-console.
Use BFormSelect with Not specified/Yes/No options instead, which
accepts null as a valid model value for the tri-state scenario.
- Move inline `import datetime` to top-level imports in tool_request_form service
- Fix misleading test name and docstring: returns_422 → returns_400
- DRY up form reset in ToolRequestForm.vue: use resetForm() in submit success handler
Previously the button was always visible below the search controls.
Now it appears contextually inside the "No results found" empty state,
grouping the call-to-action with the feedback that triggered it.

- Move button into the `queryFinished && !hasResults` block in ToolBox.vue
- Button remains hidden for anonymous users, in workflow mode, and when
  `enable_tool_request_form` config is disabled
- Fix `isConfigLoaded` in the config mock to return a `ref(true)` rather
  than a plain boolean, matching the real composable
- Add 6 tests covering button visibility: with/without results, config
  disabled, anonymous user, workflow mode, and modal open-on-click
When a workflow run fails because required tools are not installed, Galaxy
now detects which tools are missing and surfaces a one-click
'Request Installation' button so users can notify admins without leaving
the workflow run page.

Backend changes:
- workflows.py: pass missing_tool_ids as extra_error_info on the
  MessageException so the list is serialised into the JSON error response
- notifications.py: add optional tool_ids and workflow_name fields to
  ToolRequestNotificationContent so admin notifications include the
  workflow context
- tool_request_form.py: mirror the same two fields on ToolRequestFormData
  and wire them through to the notification content
- test_tool_request_form.py: add integration test that submits a request
  with tool_ids + workflow_name and verifies both appear in the admin
  notification

Frontend changes (client/src/components/Workflow/Run/):
- services.js: add WorkflowMissingToolsError class (extends Error, carries
  missingToolIds[]); update getRunData() catch to detect missing_tool_ids
  in the error response and throw the typed error before rethrowSimple()
  would strip structured data
- WorkflowMissingToolsRequest.vue: new component — shows a button with
  count badge, a GModal confirmation dialog, and uses localStorage keyed
  on the sorted tool-ID set to disable the button after a successful
  request (avoids hammering); hidden for anonymous users and when the
  feature flag enable_tool_request_form is false; falls back gracefully
  when workflowName is not yet available
- WorkflowMissingToolsRequest.test.ts: 25-test suite covering visibility
  rules (feature flag, anonymous, empty IDs), cancel path, payload shape,
  singular/plural copy, localStorage deduplication, storage-key sorting,
  in-flight disabled state, error recovery/retry, and modal re-open
- WorkflowRun.vue: import and render WorkflowMissingToolsRequest inside
  the danger BAlert when a WorkflowMissingToolsError is caught; call
  getWorkflowInfo() as a best-effort fallback to populate workflowName on
  both the standard and instance (props.instance) code paths
- schema.ts: add tool_ids and workflow_name to ToolRequestFormData type
Remove requester_name and requester_email from ToolRequestFormData and
populate them server-side from trans.user to prevent spoofing.
Update integration tests and regenerate API schema accordingly.
…s URL

- Drop requester name/email inputs (now filled server-side)
- Replace bootstrap inputs with Galaxy's FormElement for consistent UI
- Validate tool URL: only https:// links accepted
- Update tests to use suppressExpectedErrorMessages helper instead of
  silencing all console errors
tool_request notifications are admin-targeted; exposing the setting to
regular users would let them opt out of receiving notifications they
cannot receive anyway, and admins opting out would defeat the purpose.
Avoid rendering the URL as a clickable link to prevent admin-targeted
URL injection attacks where a malicious user crafts a misleading href.
arash77 added 12 commits May 4, 2026 11:17
Add ToolRequestEmailNotificationTemplateBuilder and register it in
email_templates_by_category. Add HTML and plain-text email templates
for tool installation request notifications.
…nd tests

The field was removed from ToolRequestFormData (server now reads it from
the authenticated session). Drop the stale payload property and the
'Galaxy user' fallback test that covered it.
…ver-side

Both fields are now populated from the authenticated user on the backend
(trans.user.email / trans.user.username) rather than from the form payload,
preventing spoofing. requester_email is always present for registered users;
requester_name is optional since usernames are not always set.

- ToolRequestNotificationContent: swap required/optional for the two fields
- NotificationCard: always render email, conditionally prepend name
- Email templates: same conditional rendering logic
- schema.ts: regenerated to match
@arash77 arash77 force-pushed the feature/tool-request-form branch from 3b5d3da to 21aad9f Compare May 4, 2026 10:01
@arash77 arash77 marked this pull request as ready for review May 4, 2026 13:43
@arash77 arash77 moved this from In Progress to Needs Review in Galaxy Dev - weeklies May 4, 2026
@arash77
Copy link
Copy Markdown
Member Author

arash77 commented May 4, 2026

I will rename this feature to tool installation request as we discussed in the dev meeting.

@arash77 arash77 moved this from Needs Review to In Progress in Galaxy Dev - weeklies May 5, 2026
@arash77 arash77 marked this pull request as draft May 5, 2026 11:00
When `force_sync=True` is passed to `send_notification_internal`, the
notification row was created and SSE events fired, but email (and any
other async channel) was never dispatched because the channel plugins are
only registered when celery tasks are enabled. This meant tool-request
notifications — which the service layer explicitly forces to sync so the
client gets a response ID — would not deliver email to admins.

Changes:
- Add `_dispatch_notification_via_channels` to `NotificationManager` that
  marks the row dispatched and then calls `_dispatch_notification_to_users`,
  mirroring the pattern in `dispatch_pending_notifications_via_channels`.
- Call it inside `send_notification_internal` when `force_sync=True` and
  celery is enabled (i.e. channels are registered).
- Deduplicate the sync/async branching that was duplicated between
  `NotificationService.send_notification_internal` and the manager: the
  service now delegates directly to the manager.
- Make `contact_email` and `notification_settings_url` on
  `NotificationContext` `Optional` (the builder already produced `None`
  for both when config is absent; templates already guard with `{% if %}`).
- Add unit test asserting email channel fires on `force_sync=True`.
- Add integration test with mock SMTP verifying end-to-end email delivery
  for tool-request submissions when celery tasks are enabled.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

Tool request form on usegalaxy instances

3 participants