mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-10-06 11:57:16 +08:00
Create a modal for item assignment from inventory page [SCI-8250]
- Fix the behavior of the search_select. - Fix select options positioning. - Get the items to assign from selected rows. - Style the modal. Style the modal [SCI-8250] Fix select options positioning [SCI-8250]
This commit is contained in:
parent
443cd21090
commit
5f8eafedf9
7 changed files with 225 additions and 88 deletions
|
@ -278,6 +278,10 @@ var RepositoryDatatable = (function(global) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateSelectedRowsForAssignments() {
|
||||||
|
window.AssignItemsToTaskModalComponent.setShowCallback(() => rowsSelected);
|
||||||
|
}
|
||||||
|
|
||||||
function checkAvailableColumns() {
|
function checkAvailableColumns() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: $(TABLE_ID).data('available-columns'),
|
url: $(TABLE_ID).data('available-columns'),
|
||||||
|
@ -732,6 +736,7 @@ var RepositoryDatatable = (function(global) {
|
||||||
})
|
})
|
||||||
|
|
||||||
initRowSelection();
|
initRowSelection();
|
||||||
|
updateSelectedRowsForAssignments();
|
||||||
// $(window).resize(() => {
|
// $(window).resize(() => {
|
||||||
// setTimeout(() => {
|
// setTimeout(() => {
|
||||||
// adjustTableHeader();
|
// adjustTableHeader();
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
.assign-items-to-task-modal-container {
|
||||||
|
.modal-header {
|
||||||
|
padding: 1rem;
|
||||||
|
display: flex;
|
||||||
|
color: $color-volcano;
|
||||||
|
font-size: $font-size-h2;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
.close {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
color: $color-volcano;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
|
||||||
|
.level-selector {
|
||||||
|
flex-direction: column;
|
||||||
|
display: flex;
|
||||||
|
gap: .25rem;
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-bottom: 0;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: $font-size-h6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ Vue.prototype.i18n = window.I18n;
|
||||||
function initAssignItemsToTaskModalComponent() {
|
function initAssignItemsToTaskModalComponent() {
|
||||||
const container = $('.assign-items-to-task-modal-container');
|
const container = $('.assign-items-to-task-modal-container');
|
||||||
if (container.length) {
|
if (container.length) {
|
||||||
window.AssignItemsToTaskModalComponent = new Vue({
|
window.AssignItemsToTaskModalComponentContainer = new Vue({
|
||||||
el: '.assign-items-to-task-modal-container',
|
el: '.assign-items-to-task-modal-container',
|
||||||
name: 'AssignItemsToTaskModalComponent',
|
name: 'AssignItemsToTaskModalComponent',
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
role="dialog"
|
role="dialog"
|
||||||
aria-labelledby="assignItemsToTaskModalLabel"
|
aria-labelledby="assignItemsToTaskModalLabel"
|
||||||
>
|
>
|
||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog modal-sm" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 class="modal-title">
|
<h4 class="modal-title">
|
||||||
|
@ -29,23 +29,39 @@
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="project-selector">
|
<div class="project-selector level-selector">
|
||||||
<label>
|
<label>
|
||||||
{{ i18n.t("repositories.modal_assign_items_to_task.body.project_select.label") }}
|
{{
|
||||||
|
i18n.t(
|
||||||
|
"repositories.modal_assign_items_to_task.body.project_select.label"
|
||||||
|
)
|
||||||
|
}}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<SelectSearch
|
<SelectSearch
|
||||||
ref="projectsSelector"
|
ref="projectsSelector"
|
||||||
@change="changeProject"
|
@change="changeProject"
|
||||||
:options="projects"
|
:options="projects"
|
||||||
:placeholder="i18n.t('repositories.modal_assign_items_to_task.body.project_select.placeholder')"
|
:placeholder="
|
||||||
:searchPlaceholder="i18n.t('repositories.modal_assign_items_to_task.body.project_select.placeholder')"
|
i18n.t(
|
||||||
|
'repositories.modal_assign_items_to_task.body.project_select.placeholder'
|
||||||
|
)
|
||||||
|
"
|
||||||
|
:searchPlaceholder="
|
||||||
|
i18n.t(
|
||||||
|
'repositories.modal_assign_items_to_task.body.project_select.placeholder'
|
||||||
|
)
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="experiment-selector">
|
<div class="experiment-selector level-selector">
|
||||||
<label>
|
<label>
|
||||||
{{ i18n.t("repositories.modal_assign_items_to_task.body.experiment_select.label") }}
|
{{
|
||||||
|
i18n.t(
|
||||||
|
"repositories.modal_assign_items_to_task.body.experiment_select.label"
|
||||||
|
)
|
||||||
|
}}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<SelectSearch
|
<SelectSearch
|
||||||
|
@ -54,13 +70,21 @@
|
||||||
@change="changeExperiment"
|
@change="changeExperiment"
|
||||||
:options="experiments"
|
:options="experiments"
|
||||||
:placeholder="experimentsSelectorPlaceholder"
|
:placeholder="experimentsSelectorPlaceholder"
|
||||||
:searchPlaceholder="i18n.t('repositories.modal_assign_items_to_task.body.experiment_select.placeholder')"
|
:searchPlaceholder="
|
||||||
|
i18n.t(
|
||||||
|
'repositories.modal_assign_items_to_task.body.experiment_select.placeholder'
|
||||||
|
)
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="task-selector">
|
<div class="task-selector level-selector">
|
||||||
<label>
|
<label>
|
||||||
{{ i18n.t("repositories.modal_assign_items_to_task.body.task_select.label") }}
|
{{
|
||||||
|
i18n.t(
|
||||||
|
"repositories.modal_assign_items_to_task.body.task_select.label"
|
||||||
|
)
|
||||||
|
}}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<SelectSearch
|
<SelectSearch
|
||||||
|
@ -68,16 +92,28 @@
|
||||||
ref="tasksSelector"
|
ref="tasksSelector"
|
||||||
@change="changeTask"
|
@change="changeTask"
|
||||||
:options="tasks"
|
:options="tasks"
|
||||||
:placeholder="i18n.t('repositories.modal_assign_items_to_task.body.task_select.disabled_placeholder')"
|
:placeholder="
|
||||||
:searchPlaceholder="i18n.t('repositories.modal_assign_items_to_task.body.task_select.placeholder')"
|
i18n.t(
|
||||||
|
'repositories.modal_assign_items_to_task.body.task_select.disabled_placeholder'
|
||||||
|
)
|
||||||
|
"
|
||||||
|
:searchPlaceholder="
|
||||||
|
i18n.t(
|
||||||
|
'repositories.modal_assign_items_to_task.body.task_select.placeholder'
|
||||||
|
)
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-primary" data-dismiss="modal">
|
<button
|
||||||
{{
|
type="button"
|
||||||
i18n.t("repositories.modal_assign_items_to_task.assign")
|
class="btn btn-primary"
|
||||||
}}
|
data-dismiss="modal"
|
||||||
|
:disabled="!selectedTask"
|
||||||
|
@click="assign"
|
||||||
|
>
|
||||||
|
{{ i18n.t("repositories.modal_assign_items_to_task.assign") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -86,77 +122,90 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import SelectSearch from '../shared/select_search.vue'
|
import SelectSearch from "../shared/select_search.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "AssignItemsToTaskModalContainer",
|
name: "AssignItemsToTaskModalContainer",
|
||||||
props: {
|
props: {
|
||||||
visibility: Boolean,
|
visibility: Boolean,
|
||||||
urls: Object,
|
urls: Object
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
projects: [
|
rowsToAssign: [],
|
||||||
[1, "project1"],
|
projects: [],
|
||||||
[2, "project2"],
|
experiments: [],
|
||||||
[3, "project3"],
|
tasks: [],
|
||||||
[4, "project4"],
|
|
||||||
[5, "project5"],
|
|
||||||
[6, "project6"],
|
|
||||||
[7, "project7"],
|
|
||||||
[8, "project8"],
|
|
||||||
],
|
|
||||||
experiments: [
|
|
||||||
[1, "experiment1"],
|
|
||||||
[2, "experiment2"],
|
|
||||||
[3, "experiment3"],
|
|
||||||
[4, "experiment4"],
|
|
||||||
[5, "experiment5"],
|
|
||||||
[6, "experiment6"],
|
|
||||||
[7, "experiment7"],
|
|
||||||
[8, "experiment8"],
|
|
||||||
],
|
|
||||||
tasks: [
|
|
||||||
[1, "task1"],
|
|
||||||
[2, "task2"],
|
|
||||||
[3, "task3"],
|
|
||||||
[4, "task4"],
|
|
||||||
[5, "task5"],
|
|
||||||
[6, "task6"],
|
|
||||||
[7, "task7"],
|
|
||||||
[8, "task8"],
|
|
||||||
],
|
|
||||||
selectedProject: null,
|
selectedProject: null,
|
||||||
selectedExperiment: null,
|
selectedExperiment: null,
|
||||||
selectedTask: null
|
selectedTask: null,
|
||||||
|
showCallback: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
SelectSearch
|
SelectSearch
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
window.AssignItemsToTaskModalComponent = this;
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
$.get(this.urls.projects)
|
$(this.$refs.modal).on("shown.bs.modal", () => {
|
||||||
$(this.$refs.modal).on('hidden.bs.modal', () => {
|
$.get(this.projectURL, data => {
|
||||||
this.$emit('close');
|
if (Array.isArray(data)) {
|
||||||
|
this.projects = data;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.projects = [];
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$(this.$refs.modal).on("hidden.bs.modal", () => {
|
||||||
|
this.$emit("close");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
delete window.AssignItemsToTaskModalComponent;
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
experimentsSelectorPlaceholder() {
|
experimentsSelectorPlaceholder() {
|
||||||
if (this.selectedProject) {
|
if (this.selectedProject) {
|
||||||
return this.i18n.t('repositories.modal_assign_items_to_task.body.experiment_select.placeholder');
|
return this.i18n.t(
|
||||||
|
"repositories.modal_assign_items_to_task.body.experiment_select.placeholder"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return this.i18n.t('repositories.modal_assign_items_to_task.body.experiment_select.disabled_placeholder')
|
return this.i18n.t(
|
||||||
|
"repositories.modal_assign_items_to_task.body.experiment_select.disabled_placeholder"
|
||||||
|
);
|
||||||
},
|
},
|
||||||
tasksSelectorPlaceholder() {
|
tasksSelectorPlaceholder() {
|
||||||
if (this.selectedExperiment) {
|
if (this.selectedExperiment) {
|
||||||
return this.i18n.t('repositories.modal_assign_items_to_task.body.task_select.placeholder');
|
return this.i18n.t(
|
||||||
|
"repositories.modal_assign_items_to_task.body.task_select.placeholder"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return this.i18n.t('repositories.modal_assign_items_to_task.body.task_select.disabled_placeholder')
|
return this.i18n.t(
|
||||||
|
"repositories.modal_assign_items_to_task.body.task_select.disabled_placeholder"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
projectURL() {
|
||||||
|
return `${this.urls.projects}`;
|
||||||
|
},
|
||||||
|
experimentURL() {
|
||||||
|
return `${this.urls.experiments}?project_id=${this.selectedProject ||
|
||||||
|
""}`;
|
||||||
|
},
|
||||||
|
taskURL() {
|
||||||
|
return `${this.urls.tasks}?experiment_id=${this.selectedExperiment ||
|
||||||
|
""}`;
|
||||||
|
},
|
||||||
|
assignURL() {
|
||||||
|
return this.urls.assign.replace(":module_id", this.selectedTask);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
visibility(newVal) {
|
visibility() {
|
||||||
if (newVal) {
|
if (this.visibility) {
|
||||||
this.showModal();
|
this.showModal();
|
||||||
} else {
|
} else {
|
||||||
this.hideModal();
|
this.hideModal();
|
||||||
|
@ -165,33 +214,76 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showModal() {
|
showModal() {
|
||||||
$(this.$refs.modal).modal('show');
|
$(this.$refs.modal).modal("show");
|
||||||
|
|
||||||
|
this.rowsToAssign = this.showCallback();
|
||||||
},
|
},
|
||||||
hideModal(){
|
hideModal() {
|
||||||
$(this.$refs.modal).modal('hide');
|
$(this.$refs.modal).modal("hide");
|
||||||
},
|
},
|
||||||
changeProject(value) {
|
changeProject(value) {
|
||||||
const newProjectVal = value;
|
this.selectedProject = value;
|
||||||
this.selectedProject = null;
|
this.resetExperimentSelector();
|
||||||
this.selectedExperiment = null;
|
this.resetTaskSelector();
|
||||||
this.selectedTask = null;
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this.experiments = [
|
|
||||||
[1, 'ex1'],
|
|
||||||
[2, 'ex2'],
|
|
||||||
[3, 'ex3'],
|
|
||||||
[4, 'ex4']
|
|
||||||
];
|
|
||||||
this.selectedProject = newProjectVal;
|
|
||||||
}, 2000);
|
|
||||||
|
|
||||||
|
$.get(this.experimentURL, data => {
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
this.experiments = data;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.experiments = [];
|
||||||
|
});
|
||||||
},
|
},
|
||||||
changeExperiment(value) {
|
changeExperiment(value) {
|
||||||
this.selectedExperiment = value;
|
this.selectedExperiment = value;
|
||||||
|
this.resetTaskSelector();
|
||||||
|
|
||||||
|
$.get(this.taskURL, data => {
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
this.tasks = data;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.tasks = [];
|
||||||
|
});
|
||||||
},
|
},
|
||||||
changeTask(value) {
|
changeTask(value) {
|
||||||
this.selectedTask = value;
|
this.selectedTask = value;
|
||||||
|
},
|
||||||
|
resetProjectSelector() {
|
||||||
|
this.projects = [];
|
||||||
|
this.selectedProject = null;
|
||||||
|
},
|
||||||
|
resetExperimentSelector() {
|
||||||
|
this.experiments = [];
|
||||||
|
this.selectedExperiment = null;
|
||||||
|
},
|
||||||
|
resetTaskSelector() {
|
||||||
|
this.tasks = [];
|
||||||
|
this.selectedTask = null;
|
||||||
|
},
|
||||||
|
resetSelectors() {
|
||||||
|
this.resetTaskSelector();
|
||||||
|
this.resetExperimentSelector();
|
||||||
|
this.resetProjectSelector();
|
||||||
|
},
|
||||||
|
assign() {
|
||||||
|
if (!this.selectedTask) return;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: this.assignURL,
|
||||||
|
type: "PATCH",
|
||||||
|
dataType: "json",
|
||||||
|
data: { rows_to_assign: this.rowsToAssign }
|
||||||
|
}).always(() => {
|
||||||
|
this.resetSelectors();
|
||||||
|
this.deselectRows();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setShowCallback(callback) {
|
||||||
|
this.showCallback = callback;
|
||||||
|
},
|
||||||
|
deselectRows() {
|
||||||
|
$('.repository-row-selector:checked').trigger('click');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
this.$emit('blur');
|
this.$emit('blur');
|
||||||
}, 100)
|
}, 200)
|
||||||
},
|
},
|
||||||
toggle() {
|
toggle() {
|
||||||
this.isOpen = !this.isOpen;
|
this.isOpen = !this.isOpen;
|
||||||
|
@ -71,12 +71,11 @@
|
||||||
this.$emit('change', this.value);
|
this.$emit('change', this.value);
|
||||||
},
|
},
|
||||||
updateOptionPosition() {
|
updateOptionPosition() {
|
||||||
let rect = this.$refs.container.getBoundingClientRect();
|
const rect = this.$refs.container.getBoundingClientRect();
|
||||||
let top =rect.top + rect.height;
|
const top = rect.height;
|
||||||
let left = rect.left;
|
const width = rect.width;
|
||||||
let width = rect.width;
|
|
||||||
|
|
||||||
this.optionPositionStyle = `position: fixed; top: ${top}px; left: ${left}px; width: ${width}px`
|
this.optionPositionStyle = `position: absolute; top: ${top}px; width: ${width}px`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,16 +42,20 @@
|
||||||
} else {
|
} else {
|
||||||
this.currentOptions = this.options.filter((o) => o[1].toLowerCase().includes(this.query.toLowerCase()));
|
this.currentOptions = this.options.filter((o) => o[1].toLowerCase().includes(this.query.toLowerCase()));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
options() {
|
||||||
|
this.currentOptions = this.options;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
valueLabel() {
|
valueLabel() {
|
||||||
let option = this.options.find((o) => o[0] === this.value);
|
let option = this.currentOptions.find((o) => o[0] === this.value);
|
||||||
return option && option[1];
|
return option && option[1];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
blur() {
|
blur() {
|
||||||
|
this.isOpen = false;
|
||||||
this.$emit('blur');
|
this.$emit('blur');
|
||||||
},
|
},
|
||||||
change(value) {
|
change(value) {
|
||||||
|
@ -68,7 +72,7 @@
|
||||||
this.$emit('close');
|
this.$emit('close');
|
||||||
},
|
},
|
||||||
fetchOptions() {
|
fetchOptions() {
|
||||||
$.get(`/${this.optionsUrl}?query=${this.query}`,
|
$.get(`${this.optionsUrl}?query=${this.query || ''}`,
|
||||||
(data) => {
|
(data) => {
|
||||||
this.currentOptions = data;
|
this.currentOptions = data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<div
|
<div
|
||||||
class="assign-items-to-task-modal-container"
|
class="assign-items-to-task-modal-container"
|
||||||
data-assign-url=<%= my_module_repository_path(MyModule.first) %>
|
data-assign-url="<%= my_module_repository_path(":module_id") %>"
|
||||||
data-projects-url=<%= project_filter_projects_path %>
|
data-projects-url="<%= project_filter_projects_path %>"
|
||||||
data-experiments-url=<%= experiment_filter_experiments_path %>
|
data-experiments-url="<%= experiment_filter_experiments_path %>"
|
||||||
data-tasks-url=<%= module_filter_my_modules_path %>
|
data-tasks-url="<%= module_filter_my_modules_path %>"
|
||||||
>
|
>
|
||||||
<assign-items-to-task-modal-container
|
<assign-items-to-task-modal-container
|
||||||
:visibility="visibility"
|
:visibility="visibility"
|
||||||
|
|
Loading…
Add table
Reference in a new issue