Merge pull request #8258 from andrej-scinote/aj_SCI_11558

Create new item from task [SCI-11558]
This commit is contained in:
andrej-scinote 2025-02-25 09:01:12 +01:00 committed by GitHub
commit b25ebf4324
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 202 additions and 13 deletions

View file

@ -82,9 +82,27 @@ class RepositoryRowsController < ApplicationController
record_annotation_notification(repository_row, repository_cell)
end
if update_params[:my_module_id].present?
my_module = MyModule.viewable_by_user(current_user, current_team).find_by(id: update_params[:my_module_id])
return render_403 unless my_module.present? && can_read_my_module?(my_module)
ActiveRecord::Base.transaction do
service_assign = RepositoryRows::MyModuleAssignUnassignService.call(
my_module: my_module,
repository: @repository,
user: current_user,
params: { rows_to_assign: [repository_row.id] }
)
render json: service_assign.errors, status: :bad_request unless service_assign.succeed?
end
end
render json: { id: service.repository_row.id, flash: t('repositories.create.success_flash',
record: escape_input(repository_row.name),
repository: escape_input(@repository.name)) },
repository: escape_input(@repository.name)),
repository_row_url: repository_repository_row_path(@repository, repository_row) },
status: :ok
else
render json: service.errors, status: :bad_request
@ -480,7 +498,7 @@ class RepositoryRowsController < ApplicationController
end
def update_params
params.permit(repository_row: :name, repository_cells: {}).to_h
params.permit(:my_module_id, :is_output, repository_row: :name, repository_cells: {}).to_h
end
def log_activity(type_of, repository_row, message_items = {})

View file

@ -108,7 +108,7 @@ module RepositoryDatatableHelper
repository_rows.map do |record|
row = {
DT_RowId: record.id,
DT_RowAttr: { 'data-state': row_style(record) },
DT_RowAttr: { 'data-state': simple_row_style(record, my_module) },
'0': escape_input(record.name),
recordInfoUrl: Rails.application.routes.url_helpers.repository_repository_row_path(record.repository, record),
rowRemindersUrl:
@ -305,6 +305,14 @@ module RepositoryDatatableHelper
''
end
def simple_row_style(row, my_module)
style = []
style << I18n.t('general.archived') if row.archived
style << I18n.t('general.output') if row.output? && row.my_module.id == my_module&.id
style
end
def stock_consumption_permitted?(repository, my_module)
return false unless repository.is_a?(Repository) && current_user

View file

@ -6,7 +6,10 @@
{{ i18n.t('my_modules.assigned_items.title') }}
<span class="text-sn-grey-500 font-normal text-base">[{{ totalRows }}]</span>
</h2>
<div class="ml-auto">
<div class="flex gap-6 ml-auto">
<button class="btn btn-secondary" @click="openCreateItemModal=true">
{{ i18n.t('my_modules.assigned_items.create_item') }}
</button>
<!-- Next block just for legacy support, JQuery not good works with Teleport -->
<div class="hidden repository-assign"
v-for="repository in availableRepositories"
@ -20,8 +23,9 @@
<!-- End of block -->
<GeneralDropdown position="right" @open="loadAvailableRepositories">
<template v-slot:field>
<button class="btn btn-light">
<button class="btn btn-secondary">
{{ i18n.t('my_modules.assigned_items.assign_from') }}
<span class="sn-icon sn-icon-down"></span>
</button>
</template>
<template v-slot:flyout>
@ -52,6 +56,15 @@
/>
</div>
</div>
<Teleport to="body">
<CreateItemModal
v-if="openCreateItemModal"
:repositoriesUrl="repositoriesUrl"
:myModuleId="myModuleId"
@tableReloaded="newCreatedRow"
@close="openCreateItemModal = false"/>
</Teleport>
</div>
</template>
@ -59,16 +72,20 @@
import axios from '../../packs/custom_axios.js';
import GeneralDropdown from '../shared/general_dropdown.vue';
import AssignedRepository from './assigned_items/repository.vue';
import CreateItemModal from './assigned_items/modals/new_item.vue';
export default {
name: 'AssignedItems',
props: {
avaialableRepositoriesUrl: String,
assignedRepositoriesUrl: String
assignedRepositoriesUrl: String,
repositoriesUrl: String,
myModuleId: String
},
components: {
GeneralDropdown,
AssignedRepository
AssignedRepository,
CreateItemModal
},
created() {
this.loadAssingedRepositories();
@ -83,7 +100,8 @@ export default {
availableRepositories: [],
assignedRepositories: [],
loadingAvailableRepositories: false,
sectionOpened: false
sectionOpened: false,
openCreateItemModal: false
};
},
methods: {
@ -111,6 +129,10 @@ export default {
this.assignedRepositories = response.data.data;
});
},
newCreatedRow(repositoryRowSidebarUrl) {
this.loadAssingedRepositories();
window.repositoryItemSidebarComponent.toggleShowHideSidebar(repositoryRowSidebarUrl, this.myModuleId, null);
},
openAssignModal(repositoryId) {
const [repository] = this.$refs[`repository_${repositoryId}`];
repository.click();

View file

@ -0,0 +1,112 @@
<template>
<div ref="modal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<form @submit.prevent="submit">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<i class="sn-icon sn-icon-close"></i>
</button>
<h4 class="modal-title truncate !block" >
{{ i18n.t('my_modules.assigned_items.create_modal.modal_title') }}
</h4>
</div>
<div class="modal-body">
<p class="mb-6">{{ i18n.t('my_modules.assigned_items.create_modal.description') }}</p>
<div class="mb-6">
<label class="sci-label">
{{ i18n.t('my_modules.assigned_items.create_modal.inventory_label') }}
</label>
<SelectDropdown :optionsUrl="repositoriesUrl" @change="changeRepository" :searchable="true" />
</div>
<div class="mb-6">
<label class="sci-label">
{{ i18n.t('my_modules.assigned_items.create_modal.inventory_item_name') }}
</label>
<div class="sci-input-container-v2">
<input
type="text"
v-model="inventoryItemName"
:placeholder="i18n.t('my_modules.assigned_items.create_modal.inventory_item_name')"
>
</div>
</div>
<div class="flex items-center gap-2.5">
<span class="sci-checkbox-container">
<input type="checkbox"
class="sci-checkbox"
v-model="outputMarked" />
<span class="sci-checkbox-label"></span>
</span>
{{ i18n.t('my_modules.assigned_items.create_modal.checkbox_label') }}
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ i18n.t('general.cancel') }}</button>
<button class="btn btn-primary" :disabled="submitting || !validObject" type="submit">
{{ i18n.t('my_modules.assigned_items.create_modal.create_item') }}
</button>
</div>
</div>
</form>
</div>
</div>
</template>
<script>
import axios from '../../../../packs/custom_axios.js';
import SelectDropdown from '../../../shared/select_dropdown.vue';
import modalMixin from '../../../shared/modal_mixin.js';
import {
repository_repository_rows_path
} from '../../../../routes.js';
export default {
name: 'CreateItemModal',
props: {
repositoriesUrl: String,
myModuleId: String
},
mixins: [modalMixin],
components: {
SelectDropdown
},
data() {
return {
selectedRepository: null,
inventoryItemName: '',
outputMarked: false,
submitting: false
};
},
computed: {
validObject() {
return this.selectedRepository && this.inventoryItemName;
}
},
created() {
},
mounted() {
},
methods: {
changeRepository(repository) {
this.selectedRepository = repository;
},
submit() {
this.submitting = true;
axios.post(repository_repository_rows_path(this.selectedRepository), {
repository_row: { name: this.inventoryItemName },
my_module_id: this.myModuleId,
is_output: this.outputMarked
}).then((data) => {
this.$emit('tableReloaded', data.data.repository_row_url);
this.submitting = false;
this.close();
}).catch(() => {
this.submitting = false;
});
}
}
};
</script>

View file

@ -10,14 +10,16 @@
<ul v-html="reminders" class="list-none pl-0"></ul>
</template>
</GeneralDropdown>
<a class="hover:no-underline flex items-center gap-1 record-info-link"
<a class="hover:no-underline record-info-link truncate block"
:title="params.data[0]"
:href="params.data.recordInfoUrl"
>
<span class="truncate">
{{ params.data[0] }}
</span>
{{ params.data[0] }}
</a>
<span v-for="state in params.data.DT_RowAttr['data-state']" class="text-sn-grey bg-sn-light-grey text-xs px-1.5 py-1 ">
{{ state }}
</span>
</div>
</template>

View file

@ -22,6 +22,7 @@ class RepositoryRow < ApplicationRecord
class_name: 'User',
inverse_of: :restored_repository_rows,
optional: true
belongs_to :my_module, optional: true
has_many :repository_cells, -> { order(:id) }, inverse_of: :repository_row, dependent: :destroy
{
@ -238,4 +239,8 @@ class RepositoryRow < ApplicationRecord
def archived_branch?
archived?
end
def output?
my_module_id.present?
end
end

View file

@ -6,12 +6,13 @@ module RepositoryRows
attr_reader :repository, :params, :errors, :repository_row
def initialize(repository:, user:, params:)
def initialize(repository:, user:, params:, my_module: nil)
@repository = repository
@user = user
@params = params
@errors = {}
@repository_row = nil
@my_module = my_module
end
def call
@ -20,7 +21,9 @@ module RepositoryRows
ActiveRecord::Base.transaction do
@repository_row = @repository.repository_rows.new(params[:repository_row])
@repository_row.last_modified_by = @user
@repository_row.my_module = @my_module
@repository_row.created_by = @user
@repository_row.my_module_id = params[:my_module_id] if params[:my_module_id] && params[:is_output]
@repository_row.save!
params[:repository_cells]&.each do |column_id, value|

View file

@ -84,6 +84,8 @@
ref="assignedItems"
avaialable-repositories-url="<%= my_module_repositories_dropdown_list_path(@my_module) %>"
assigned-repositories-url="<%= my_module_repositories_list_path(@my_module) %>"
repositories-url="<%= list_team_repositories_path(current_team) %>"
my-module-id="<%= @my_module.id%>"
/>
</div>
<!-- Assigned items -->

View file

@ -1326,6 +1326,15 @@ en:
assigned_items:
title: "Assigned items"
assign_from: "Assign from"
create_item: "Create item"
create_modal:
modal_title: 'Create a new item'
description: 'Choose an inventory and name the new item'
inventory_label: 'Inventory'
inventory_placeholder: 'Select inventory'
inventory_item_name: 'Item name'
create_item: 'Create item'
checkbox_label: 'Mark as output'
direct_assign:
success: "Successfully assigned an item to the task."
protocol:
@ -4435,6 +4444,7 @@ en:
archive: "Archive"
assign: "Assign"
options_selected: 'options selected'
output: 'Output'
# In order to use the strings 'yes' and 'no' as keys, you need to wrap them with quotes
'yes': "Yes"
'no': "No"

View file

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddMyModuleToRepositoryRow < ActiveRecord::Migration[7.0]
def change
add_reference :repository_rows, :my_module, null: true, foreign_key: true
end
end