mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-22 21:15:35 +08:00
Merge pull request #8433 from andrej-scinote/aj_SCI_11799
Add new columns to experiments table [SCI-11799]
This commit is contained in:
commit
305f689820
9 changed files with 197 additions and 6 deletions
|
@ -459,7 +459,7 @@ class ExperimentsController < ApplicationController
|
|||
end
|
||||
|
||||
def experiment_params
|
||||
params.require(:experiment).permit(:name, :description, :archived)
|
||||
params.require(:experiment).permit(:name, :description, :archived, :due_date, :start_on, :status)
|
||||
end
|
||||
|
||||
def move_experiment_param
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
@edit="edit"
|
||||
@create="create"
|
||||
@access="access"
|
||||
@updateDueDate="updateDueDate"
|
||||
@updateStartDate="updateStartDate"
|
||||
@changeStatus="changeStatus"
|
||||
>
|
||||
<template #card="data">
|
||||
<ExperimentCard :params="data.params" :dtComponent="data.dtComponent" ></ExperimentCard>
|
||||
|
@ -71,6 +74,9 @@ import MoveModal from './modals/move.vue';
|
|||
import EditModal from './modals/edit.vue';
|
||||
import NewModal from './modals/new.vue';
|
||||
import AccessModal from '../shared/access_modal/modal.vue';
|
||||
import StatusRenderer from './renderers/status.vue';
|
||||
import DueDateRenderer from '../shared/datatable/renderers/date.vue';
|
||||
import StartDateRenderer from '../shared/datatable/renderers/date.vue';
|
||||
import ExperimentCard from './card.vue';
|
||||
|
||||
export default {
|
||||
|
@ -84,7 +90,10 @@ export default {
|
|||
EditModal,
|
||||
NewModal,
|
||||
AccessModal,
|
||||
ExperimentCard
|
||||
ExperimentCard,
|
||||
StatusRenderer,
|
||||
StartDateRenderer,
|
||||
DueDateRenderer
|
||||
},
|
||||
props: {
|
||||
dataSource: { type: String, required: true },
|
||||
|
@ -124,6 +133,41 @@ export default {
|
|||
sortable: true,
|
||||
minWidth: 80
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
headerName: this.i18n.t('experiments.table.column.status_html'),
|
||||
sortable: true,
|
||||
cellRenderer: StatusRenderer,
|
||||
minWidth: 200
|
||||
},
|
||||
{
|
||||
field: 'start_date',
|
||||
headerName: this.i18n.t('experiments.table.column.start_date_html'),
|
||||
sortable: true,
|
||||
cellRenderer: StartDateRenderer,
|
||||
cellRendererParams: {
|
||||
placeholder: this.i18n.t('experiments.table.column.no_start_date_placeholder'),
|
||||
field: 'start_date_cell',
|
||||
mode: 'date',
|
||||
emptyPlaceholder: this.i18n.t('experiments.table.column.no_due_date'),
|
||||
emitAction: 'updateStartDate'
|
||||
},
|
||||
minWidth: 180
|
||||
},
|
||||
{
|
||||
field: 'due_date',
|
||||
headerName: this.i18n.t('experiments.table.column.due_date_html'),
|
||||
sortable: true,
|
||||
cellRenderer: DueDateRenderer,
|
||||
cellRendererParams: {
|
||||
placeholder: this.i18n.t('experiments.table.column.no_due_date_placeholder'),
|
||||
field: 'due_date_cell',
|
||||
mode: 'date',
|
||||
emptyPlaceholder: this.i18n.t('experiments.table.column.no_due_date'),
|
||||
emitAction: 'updateDueDate'
|
||||
},
|
||||
minWidth: 200
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
headerName: this.i18n.t('experiments.card.start_date'),
|
||||
|
@ -148,7 +192,7 @@ export default {
|
|||
|
||||
columns.push({
|
||||
field: 'completed_tasks',
|
||||
headerName: this.i18n.t('experiments.card.completed_task'),
|
||||
headerName: this.i18n.t('experiments.table.column.completed_task'),
|
||||
cellRenderer: CompletedTasksRenderer,
|
||||
sortable: true,
|
||||
minWidth: 110
|
||||
|
@ -267,6 +311,29 @@ export default {
|
|||
object: rows[0],
|
||||
roles_path: this.userRolesUrl
|
||||
};
|
||||
},
|
||||
formatDate(date) {
|
||||
if (!(date instanceof Date)) return null;
|
||||
|
||||
const y = date.getFullYear();
|
||||
const m = date.getMonth() + 1;
|
||||
const d = date.getDate();
|
||||
|
||||
return `${y}/${m}/${d}`;
|
||||
},
|
||||
updateField(url, params) {
|
||||
axios.put(url, params).then(() => {
|
||||
this.updateTable();
|
||||
});
|
||||
},
|
||||
changeStatus(value, params) {
|
||||
this.updateField(params.data.urls.update, { experiment: { status: value } });
|
||||
},
|
||||
updateDueDate(value, params) {
|
||||
this.updateField(params.data.urls.update, { due_date: this.formatDate(value) });
|
||||
},
|
||||
updateStartDate(value, params) {
|
||||
this.updateField(params.data.urls.update, { start_on: this.formatDate(value) });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
68
app/javascript/vue/experiments/renderers/status.vue
Normal file
68
app/javascript/vue/experiments/renderers/status.vue
Normal file
|
@ -0,0 +1,68 @@
|
|||
<template>
|
||||
<div v-if="params.data.status_cell.editable" class="py-0.5">
|
||||
<SelectDropdown
|
||||
:options="statuses"
|
||||
:value="params.data.status_cell.status"
|
||||
@change="changeStatus"
|
||||
size="xs"
|
||||
:borderless="true"
|
||||
:optionRenderer="optionRenderer"
|
||||
:labelRenderer="optionRenderer"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="flex items-center gap-2 py-0.5">
|
||||
<div class="w-3 h-3 rounded-full"
|
||||
:class="this.statusColor(params.data.status_cell.status)"></div>
|
||||
<span class="truncate">
|
||||
{{ this.i18n.t(`experiments.table.column.status.${params.data.status_cell.status}`) }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import SelectDropdown from '../../shared/select_dropdown.vue';
|
||||
|
||||
export default {
|
||||
name: 'StatusRenderer',
|
||||
components: {
|
||||
SelectDropdown
|
||||
},
|
||||
props: {
|
||||
params: {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
statuses: [
|
||||
['not_started', this.i18n.t('experiments.table.column.status.not_started')],
|
||||
['started', this.i18n.t('experiments.table.column.status.started')],
|
||||
['completed', this.i18n.t('experiments.table.column.status.completed')]
|
||||
]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
statusColor(status) {
|
||||
let color = 'bg-sn-grey-500';
|
||||
if (status === 'started') {
|
||||
color = 'bg-sn-science-blue';
|
||||
} else if (status === 'completed') {
|
||||
color = 'bg-sn-alert-green';
|
||||
}
|
||||
|
||||
return color;
|
||||
},
|
||||
optionRenderer(option) {
|
||||
return `
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="${this.statusColor(option[0])} w-3 h-3 rounded-full"></div>
|
||||
<span>${option[1]}</span>
|
||||
</div>`;
|
||||
},
|
||||
changeStatus(newStatus) {
|
||||
this.params.dtComponent.$emit('changeStatus', newStatus, this.params);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -79,6 +79,7 @@ export default {
|
|||
DataTable,
|
||||
ConfirmationModal,
|
||||
DueDateRenderer,
|
||||
StartDateRenderer,
|
||||
DesignatedUsers,
|
||||
TagsModal,
|
||||
NewModal,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="w-4 h-4 rounded-full"
|
||||
class="w-3 h-3 rounded-full"
|
||||
:class="{ 'bg-sn-grey-500': params.data.status.light_color }"
|
||||
:style="!params.data.status.light_color && { backgroundColor: params.data.status.color }"
|
||||
></div>
|
||||
|
|
|
@ -555,6 +555,14 @@ class Experiment < ApplicationRecord
|
|||
true
|
||||
end
|
||||
|
||||
def overdue?(date = Date.current)
|
||||
due_date.present? && date >= due_date
|
||||
end
|
||||
|
||||
def one_day_prior?(date = Date.current)
|
||||
due_date.present? && date < due_date && date > (due_date - 1.day)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def log_activity(type_of, current_user, my_module)
|
||||
|
|
|
@ -9,7 +9,7 @@ module Lists
|
|||
|
||||
attributes :name, :code, :created_at, :updated_at, :workflow_img, :description, :completed_tasks,
|
||||
:total_tasks, :archived_on, :urls, :sa_description, :default_public_user_role_id, :team,
|
||||
:top_level_assignable, :hidden, :archived, :project_id
|
||||
:top_level_assignable, :hidden, :archived, :project_id, :due_date_cell, :start_date_cell, :status_cell
|
||||
|
||||
def created_at
|
||||
I18n.l(object.created_at, format: :full_date)
|
||||
|
@ -80,5 +80,43 @@ module Lists
|
|||
def workflow_img
|
||||
rails_blob_path(object.workflowimg, only_path: true) if object.workflowimg.attached?
|
||||
end
|
||||
|
||||
def status_cell
|
||||
{
|
||||
status: object.status,
|
||||
editable: can_manage_experiment?(object)
|
||||
}
|
||||
end
|
||||
|
||||
def due_date_cell
|
||||
{
|
||||
value: due_date,
|
||||
value_formatted: due_date,
|
||||
editable: can_manage_experiment?(object),
|
||||
icon: (if object.one_day_prior? && !object.completed?
|
||||
'sn-icon sn-icon-alert-warning text-sn-alert-brittlebush'
|
||||
elsif object.overdue? && !object.completed?
|
||||
'sn-icon sn-icon-alert-warning text-sn-delete-red'
|
||||
end)
|
||||
}
|
||||
end
|
||||
|
||||
def start_date_cell
|
||||
{
|
||||
value: start_date,
|
||||
value_formatted: start_date,
|
||||
editable: can_manage_experiment?(object)
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def due_date
|
||||
I18n.l(object.due_date, format: :full_date) if object.due_date
|
||||
end
|
||||
|
||||
def start_date
|
||||
I18n.l(object.start_on, format: :full_date) if object.start_on
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -102,7 +102,7 @@ module Lists
|
|||
{
|
||||
value: start_date,
|
||||
value_formatted: start_date_formatted,
|
||||
editable: can_update_my_module_due_date?(object)
|
||||
editable: can_update_my_module_start_date?(object)
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -1791,6 +1791,15 @@ en:
|
|||
assigned_html: 'Assigned to'
|
||||
tags_html: 'Tags'
|
||||
comments_html: 'Comments'
|
||||
status_html: 'Status'
|
||||
completed_task: 'Tasks done'
|
||||
no_due_date_placeholder: '+ Add due date'
|
||||
no_due_date: 'not set'
|
||||
no_start_date_placeholder: "+ Add starting date"
|
||||
status:
|
||||
not_started: 'Not started'
|
||||
started: 'In progress'
|
||||
completed: 'Done'
|
||||
modal_move_modules:
|
||||
title: "Move task(s) to experiment"
|
||||
confirm: "Move"
|
||||
|
|
Loading…
Add table
Reference in a new issue