Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workflow Executions: Share results #895

Merged
merged 57 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
eea92bd
Add migration to add shared_with_namespace column to workflow executions
malchua Jan 8, 2025
ee9c1c0
Add checkbox to workflow execution creation form
malchua Jan 9, 2025
b338549
Update workflow execution creation tests
malchua Jan 9, 2025
e022bdb
Define new scope for returning shared workflow executions
malchua Jan 10, 2025
fd899d2
Add shared workflow executions to list of WEs for a project
malchua Jan 10, 2025
2c1b9cc
Create new policy for getting shared workflow executions
malchua Jan 13, 2025
34ee741
Update load_workflows to add workflows shared to the Project
malchua Jan 13, 2025
d8f274c
Remove scope for getting user and shared workflows
malchua Jan 14, 2025
88f90ae
Update system tests since we added new fixtures
malchua Jan 14, 2025
49fe0c4
Add workflow execution section in Groups sidebar
malchua Jan 17, 2025
b99d04d
Create new workflow execution controller for Groups
malchua Jan 17, 2025
80a36f7
Add new workflow execution controller test file
malchua Jan 17, 2025
088c1c7
Create new policy for viewing workflow executions in Groups
malchua Jan 17, 2025
2ed0a91
Add new scope for finding shared WEs in a Group
malchua Jan 17, 2025
6066105
Add an index page for group workflow executions
malchua Jan 17, 2025
5bf25fb
Update translations
malchua Jan 17, 2025
9748460
Update group routes
malchua Jan 17, 2025
845d85e
Create test for new group_shared scope
malchua Jan 20, 2025
628990b
Fix errors for calling groups workflow executions page
malchua Jan 20, 2025
9041687
Add test for calling new workflow execution page
malchua Jan 20, 2025
14cf818
Add workflow execution table toGroups
malchua Jan 23, 2025
8958544
Update translations
malchua Jan 23, 2025
c0fcca0
Fix bug where namespace.project is called on a group
malchua Jan 23, 2025
accfd8c
Include shared workflow executions in the show route
malchua Jan 23, 2025
62cc40d
Update tests for project workflow execution controller
malchua Jan 23, 2025
5feb45e
Remove changes relating to group to move to new branch
malchua Jan 27, 2025
b404526
Fix rubocop warning
malchua Jan 27, 2025
5433ab4
Add namespace_type variable to translations
malchua Jan 27, 2025
b7ee981
Modify checkbox prompt to use proper namespace type
malchua Jan 27, 2025
7414dd8
Remove action buttons from show page
malchua Jan 27, 2025
e3ae1fe
Fix workflow executions submissions tests
malchua Jan 27, 2025
887893f
Fix format of class list
malchua Jan 28, 2025
182dfdf
Allow user actions for shared workflows they submitted
malchua Jan 28, 2025
2b34766
Update description for workflow index page
malchua Jan 28, 2025
6711441
Add UI tests to ensure shared workflows are displayed properly
malchua Jan 28, 2025
913d6ee
Simplify rendering row action logic
malchua Jan 28, 2025
196ca85
Hide prompt when creating automated workflow executions
malchua Jan 29, 2025
78fb565
Use namespace_id to get namespace_type
malchua Jan 29, 2025
900b978
Update nextflow_component_test.rb
malchua Jan 29, 2025
daeea28
Use nested translations for shared_with_namespace
malchua Jan 29, 2025
bbab543
Update component test with proper namespace ids
malchua Jan 29, 2025
edf0ccf
Update submissions_test with new translations
malchua Jan 30, 2025
38b9124
Normalize translations
malchua Jan 30, 2025
ac4a30d
Modify nextflow component to not show empty div
malchua Jan 30, 2025
e5d854d
Update workflow execution tests to be less flakey
malchua Jan 30, 2025
a7a117b
Update table to render Actions cell consistently
malchua Jan 30, 2025
c0a4281
Fix bug with exporting shared workflow executions
malchua Jan 30, 2025
4e003be
Fix table component actions cell logic
malchua Jan 31, 2025
2b2f7e7
Update workflow execution policies and tests
malchua Feb 5, 2025
4993ed8
Remove unnecessary shared_with_namespace check
malchua Feb 5, 2025
c000663
Include checkbox when using an automatable pipeline
malchua Feb 5, 2025
c0a2ced
Add new fixture files for export tests
malchua Feb 6, 2025
eb0656a
Create fixtures for export testing
malchua Feb 6, 2025
667162d
Fix policy bug when user is not submitter or bot
malchua Feb 6, 2025
ecfcfd6
Add shared workflow tests to data_exports_test
malchua Feb 6, 2025
7c93893
Fix bug where incorrect redirect path is used
malchua Feb 6, 2025
73daa19
Simplify redirect_to_project method
malchua Feb 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions app/components/nextflow_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,23 @@
t(:"components.nextflow.email_notification"),
class: "mr-2 text-sm font-medium text-slate-900 dark:text-white" %>
</div>
<%# do not render checkbox for an automated workflow execution %>
<% if @namespace_type && [email protected]? %>
<div class="flex items-center h-5 mb-4">
<%= workflow.check_box :shared_with_namespace,
{
checked:
instance.present? && instance["shared_with_namespace"],
class:
"w-4 h-4 mr-2.5 text-primary-600 bg-slate-100 border-slate-300 rounded focus:ring-primary-500 dark:focus:ring-primary-600 dark:ring-offset-slate-800 focus:ring-2 dark:bg-slate-700 dark:border-slate-600",
} %>
<%= workflow.label :shared_with_namespace,
t(
:"components.nextflow.shared_with.#{@namespace_type.downcase}",
),
class: "mr-2 text-sm font-medium text-slate-900 dark:text-white" %>
</div>
<% end %>
<% end %>

<button
Expand Down
12 changes: 9 additions & 3 deletions app/components/nextflow_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ class NextflowComponent < Component
attr_reader :schema, :url, :workflow, :metadata_fields, :samples, :namespace_id, :instance

# rubocop:disable Metrics/ParameterLists
def initialize(url:, samples:, workflow:, fields:, namespace_id:,
allowed_to_update_samples: true, instance: nil)
def initialize(url:, samples:, workflow:, fields:, namespace_id:, allowed_to_update_samples: true, instance: nil)
@samples = samples
@namespace_id = namespace_id
@url = url
@workflow = workflow
@metadata_fields = fields
@allowed_to_update_samples = allowed_to_update_samples
@instance = instance
@namespace_type = namespace_type(namespace_id)
end

# rubocop:enable Metrics/ParameterLists

def namespace_type(namespace_id)
namespace = Namespace.find_by(id: namespace_id)
return unless namespace

namespace.type
end
end
52 changes: 27 additions & 25 deletions app/components/workflow_executions/table_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -145,31 +145,33 @@
tag: 'td',
classes: class_names('px-3 py-3 sticky right-0 bg-white dark:bg-slate-800 z-10 space-x-2')
) do %>
<% if workflow_execution.cancellable? && @row_actions.key?(:cancel) %>
<%= link_to(
t(:"workflow_executions.index.actions.cancel_button"),
cancel_path(workflow_execution),
data: {
turbo_stream: true,
turbo_method: :put,
turbo_confirm: t(:"workflow_executions.index.actions.cancel_confirm"),
},
class:
"font-medium text-blue-600 underline dark:text-blue-500 hover:no-underline cursor-pointer",
) %>
<% end %>
<% if workflow_execution.deletable? && @row_actions.key?(:destroy) %>
<%= link_to(
t(:"workflow_executions.index.actions.delete_button"),
individual_path(workflow_execution),
data: {
turbo_stream: true,
turbo_method: :delete,
turbo_confirm: t(:"workflow_executions.index.actions.delete_confirm"),
},
class:
"font-medium text-blue-600 underline dark:text-blue-500 hover:no-underline cursor-pointer",
) %>
<% if !workflow_execution.shared_with_namespace || @namespace.nil? %>
<% if workflow_execution.cancellable? && @row_actions.key?(:cancel) %>
<%= link_to(
t(:"workflow_executions.index.actions.cancel_button"),
cancel_path(workflow_execution),
data: {
turbo_stream: true,
turbo_method: :put,
turbo_confirm: t(:"workflow_executions.index.actions.cancel_confirm"),
},
class:
"font-medium text-blue-600 underline dark:text-blue-500 hover:no-underline cursor-pointer",
) %>
<% end %>
<% if workflow_execution.deletable? && @row_actions.key?(:destroy) %>
<%= link_to(
t(:"workflow_executions.index.actions.delete_button"),
individual_path(workflow_execution),
data: {
turbo_stream: true,
turbo_method: :delete,
turbo_confirm: t(:"workflow_executions.index.actions.delete_confirm"),
},
class:
"font-medium text-blue-600 underline dark:text-blue-500 hover:no-underline cursor-pointer",
) %>
<% end %>
<% end %>
<% end %>
<% end %>
Expand Down
2 changes: 1 addition & 1 deletion app/components/workflow_executions/table_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def cancel_path(workflow_execution)
end

def individual_path(workflow_execution)
if @namespace
if @namespace && @namespace.type == 'Project'
namespace_project_workflow_execution_path(
@namespace.parent,
@namespace.project,
Expand Down
5 changes: 2 additions & 3 deletions app/controllers/data_exports_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,10 @@ def redirect_to_project

def redirect_to_workflow_execution
workflow_execution = WorkflowExecution.find_by(id: params['identifier'])
submitter = workflow_execution.submitter
if submitter.user_type == 'human'
if workflow_execution.submitter == current_user
redirect_to workflow_execution_path(workflow_execution)
else
namespace = Namespace.find_by(puid: submitter.first_name)
namespace = workflow_execution.namespace
redirect_to namespace_project_workflow_execution_path(namespace.parent, namespace.project, workflow_execution)
end
end
Expand Down
11 changes: 9 additions & 2 deletions app/controllers/projects/workflow_executions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,22 @@ def namespace
end

def workflow_execution
@workflow_execution = WorkflowExecution.find_by!(id: params[:id], submitter: @project.namespace.automation_bot)
@workflow_execution = WorkflowExecution.find_by(
id: params[:id],
submitter: @project.namespace.automation_bot,
shared_with_namespace: false
) || WorkflowExecution.find_by(id: params[:id], namespace:, shared_with_namespace: true)

raise ActiveRecord::RecordNotFound if @workflow_execution.nil?
end

def workflow_execution_update_params
params.require(:workflow_execution).permit(:name)
end

def load_workflows
authorized_scope(WorkflowExecution, type: :relation, as: :automated, scope_options: { project: @project })
authorized_scope(WorkflowExecution, type: :relation, as: :automated_and_shared,
scope_options: { project: @project })
end

def current_page
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ def pipeline_selection
end

def create
@namespace = Namespace.find_by(id: @namespace_id)
fields_for_namespace(
namespace: Namespace.find_by(id: @namespace_id),
namespace: @namespace,
show_fields: true
)
render status: :ok
Expand Down
1 change: 1 addition & 0 deletions app/controllers/workflow_executions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def workflow_execution_params_attributes
:namespace_id,
:update_samples,
:email_notification,
:shared_with_namespace,
{ metadata: {},
workflow_params: {},
samples_workflow_executions_attributes: samples_workflow_execution_params_attributes }
Expand Down
65 changes: 39 additions & 26 deletions app/policies/workflow_execution_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,13 @@ def project_automation_bot?(user)
User.user_types[user.user_type] == User.user_types[:project_automation_bot]
end

def destroy? # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
unless project_automation_bot?(user)
return true if record.submitter.id == user.id
return true if Member::AccessLevel.manageable.include?(effective_access_level)
end
def destroy? # rubocop:disable Metrics/AbcSize
return true if record.submitter.id == user.id

# submitted by automation bot and user has managable access
if (record.namespace.type == Namespaces::ProjectNamespace.sti_name) &&
(record.submitter.id == record.namespace.automation_bot.id) &&
(record.namespace.automation_bot.id == user.id) &&
Member::AccessLevel.manageable.include?(effective_access_level(record.namespace.automation_bot))
Member::AccessLevel.manageable.include?(effective_access_level)
return true
end

Expand All @@ -40,18 +37,18 @@ def destroy? # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
end

def read? # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
unless project_automation_bot?(user)
return true if record.submitter.id == user.id
return true if effective_access_level(user) > Member::AccessLevel::NO_ACCESS
end
return true if record.submitter.id == user.id

# submitted by automation bot and user has access
if (record.namespace.type == Namespaces::ProjectNamespace.sti_name) &&
(record.submitter.id == record.namespace.automation_bot.id) &&
(record.namespace.automation_bot.id == user.id) &&
(effective_access_level(record.namespace.automation_bot) > Member::AccessLevel::NO_ACCESS)
record.namespace.automation_bot && (record.submitter.id == record.namespace.automation_bot.id) &&
(effective_access_level > Member::AccessLevel::NO_ACCESS)
return true
end

# shared by submitter to namespace
return true if record.shared_with_namespace && (effective_access_level > Member::AccessLevel::NO_ACCESS)

details[:id] = record.id
false
end
Expand All @@ -64,16 +61,13 @@ def create?
false
end

def cancel? # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
unless project_automation_bot?(user)
return true if record.submitter.id == user.id
return true if Member::AccessLevel.manageable.include?(effective_access_level)
end
def cancel? # rubocop:disable Metrics/AbcSize
return true if record.submitter.id == user.id

# submitted by automation bot and user has managable access
if (record.namespace.type == Namespaces::ProjectNamespace.sti_name) &&
(record.submitter.id == record.namespace.automation_bot.id) &&
(record.namespace.automation_bot.id == user.id) &&
Member::AccessLevel.manageable.include?(effective_access_level(record.namespace.automation_bot))
record.namespace.automation_bot && (record.submitter.id == record.namespace.automation_bot.id) &&
Member::AccessLevel.manageable.include?(effective_access_level)
return true
end

Expand All @@ -82,17 +76,29 @@ def cancel? # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
false
end

def edit?
def edit? # rubocop:disable Metrics/AbcSize
return true if record.submitter.id == user.id
return true if effective_access_level >= Member::AccessLevel::ANALYST

# submitted by automation bot and user is analyst or higher
if (record.namespace.type == Namespaces::ProjectNamespace.sti_name) &&
record.namespace.automation_bot && (record.submitter.id == record.namespace.automation_bot.id) &&
(effective_access_level >= Member::AccessLevel::ANALYST)
return true
end

details[:id] = record.id
false
end

def update?
def update? # rubocop:disable Metrics/AbcSize
return true if record.submitter.id == user.id
return true if effective_access_level >= Member::AccessLevel::ANALYST

# submitted by automation bot and user is analyst or higher
if (record.namespace.type == Namespaces::ProjectNamespace.sti_name) &&
record.namespace.automation_bot && (record.submitter.id == record.namespace.automation_bot.id) &&
(effective_access_level >= Member::AccessLevel::ANALYST)
return true
end

details[:id] = record.id
false
Expand All @@ -109,4 +115,11 @@ def update?

relation.where(submitter_id: user.id)
end

scope_for :relation, :automated_and_shared do |relation, options|
project = options[:project]

relation.where(submitter: project.namespace.automation_bot)
.or(relation.where(namespace_id: project.namespace.id, shared_with_namespace: true))
end
end
2 changes: 1 addition & 1 deletion app/services/data_exports/create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def authorized_export_samples(namespace, sample_ids)
def authorized_export_project_workflows
project_namespace = Namespace.find(params['export_parameters']['namespace_id'])
authorize! project_namespace, to: :export_data?
authorized_scope(WorkflowExecution, type: :relation, as: :automated,
authorized_scope(WorkflowExecution, type: :relation, as: :automated_and_shared,
scope_options: { project: project_namespace.project })
.where(id: params['export_parameters']['ids'])
end
Expand Down
5 changes: 4 additions & 1 deletion config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,9 @@ en:
nextflow:
email_notification: Receive an email notification when your analysis has completed?
required: Required
shared_with:
group: Share results with Group members?
project: Share results with Project members?
update_samples: Update samples with analysis results
pagination:
next: Next
Expand Down Expand Up @@ -1617,7 +1620,7 @@ en:
search:
placeholder: Filter by ID or name
select_all_button: Select All
subtitle: These are the workflow executions that have been automatically launched for this project
subtitle: These are the workflow executions that have been automatically launched for this project, along with workflow executions that have been shared by any of its members.
title: Workflow Executions
show:
cancel_button: Cancel
Expand Down
5 changes: 4 additions & 1 deletion config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,9 @@ fr:
nextflow:
email_notification: Receive an email notification when your analysis has completed?
required: Required
shared_with:
group: Share results with Group members?
project: Share results with Project members?
update_samples: Update samples with analysis results
pagination:
next: Next
Expand Down Expand Up @@ -1617,7 +1620,7 @@ fr:
search:
placeholder: Filter by ID or name
select_all_button: Select All
subtitle: These are the workflow executions that have been automatically launched for this project
subtitle: These are the workflow executions that have been automatically launched for this project, along with workflow executions that have been shared by any of its members.
title: Workflow Executions
show:
cancel_button: Cancel
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

# Migration to add a new shared_with_namespace column to the workflow executions table
class AddSharedWithNamespaceToWorkflowExecutions < ActiveRecord::Migration[7.2]
def change
add_column :workflow_executions, :shared_with_namespace, :boolean, default: false, null: false
end
end
1 change: 1 addition & 0 deletions db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions test/components/nextflow_component_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ class NextflowComponentTest < ViewComponentTestCase
workflow:,
samples: [sample43, sample44],
url: 'https://nf-co.re/testpipeline',
namespace_id: 'SDSDDFDSFDS',
namespace_id: projects(:project1).namespace,
fields: %w[metadata_1 metadata_2 metadata_3]
)

assert_selector 'form' do
assert_selector 'h1', text: 'phac-nml/iridanextexample', count: 1
assert_selector 'input[type=text][name="workflow_execution[name]"]'
assert_selector 'input[type=checkbox][name="workflow_execution[shared_with_namespace]"]'
assert_text 'Share results with Project members?'
end
end

Expand Down Expand Up @@ -155,15 +157,17 @@ class NextflowComponentTest < ViewComponentTestCase
url: 'https://github.com/phac-nml/mikrokondo',
name: 'phac-nml/mikrokondo',
description: 'Mikrokondo pipeline'
}, '0.1.2',
},
{ 'name' => '0.1.2',
'automatable' => true },
Rails.root.join('test/fixtures/files/nextflow/mikrokondo/nextflow_schema.json'),
Rails.root.join('test/fixtures/files/nextflow/samplesheet_schema.json'))

render_inline NextflowComponent.new(
workflow:,
samples: [],
url: 'https://nf-co.re/testpipeline',
namespace_id: 'SDSDDFDSFDS',
namespace_id: projects(:project1).namespace,
fields: %w[metadata_1 metadata_2 metadata_3],
instance:
)
Expand All @@ -179,6 +183,7 @@ class NextflowComponentTest < ViewComponentTestCase
assert_selector 'input[type="radio"][name="workflow_execution[workflow_params][skip_depth_sampling]"][value="false"][checked="checked"]',
count: 1
assert_no_selector 'input[type="radio"][name="workflow_execution[workflow_params][skip_depth_sampling]"][value="true"][checked="checked"]'
assert_no_selector 'input[type=checkbox][name="workflow_execution[shared_with_namespace]"]'
end
# rubocop:enable Layout/LineLength
end
Expand Down
Loading