mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-11-10 16:31:22 +08:00
Merge branch 'hotfix/1.36.2.1' into develop
This commit is contained in:
commit
ae25f8097e
25 changed files with 329 additions and 129 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
1.36.2
|
1.36.2.1
|
||||||
|
|
|
||||||
|
|
@ -19,5 +19,6 @@ const GLOBAL_CONSTANTS = {
|
||||||
ASSET_POLLING_INTERVAL: <%= Constants::ASSET_POLLING_INTERVAL %>,
|
ASSET_POLLING_INTERVAL: <%= Constants::ASSET_POLLING_INTERVAL %>,
|
||||||
ASSET_SYNC_URL: '<%= Constants::ASSET_SYNC_URL %>',
|
ASSET_SYNC_URL: '<%= Constants::ASSET_SYNC_URL %>',
|
||||||
GLOBAL_SEARCH_PREVIEW_LIMIT: <%= Constants::GLOBAL_SEARCH_PREVIEW_LIMIT %>,
|
GLOBAL_SEARCH_PREVIEW_LIMIT: <%= Constants::GLOBAL_SEARCH_PREVIEW_LIMIT %>,
|
||||||
SEARCH_LIMIT: <%= Constants::SEARCH_LIMIT %>
|
SEARCH_LIMIT: <%= Constants::SEARCH_LIMIT %>,
|
||||||
|
SCINOTE_EDIT_RESTRICTED_EXTENSIONS: <%= Constants::SCINOTE_EDIT_RESTRICTED_EXTENSIONS %>
|
||||||
};
|
};
|
||||||
|
|
|
||||||
14
app/javascript/vue/label_template/renderers/default.vue
Normal file
14
app/javascript/vue/label_template/renderers/default.vue
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<template>
|
||||||
|
<i v-if="params.data.default" class="sn-icon sn-icon-approval"></i>
|
||||||
|
<span v-else></span>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
params: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
17
app/javascript/vue/label_template/renderers/format.vue
Normal file
17
app/javascript/vue/label_template/renderers/format.vue
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<template>
|
||||||
|
<span>
|
||||||
|
<span v-html="params.data.icon_url"></span>
|
||||||
|
<span>{{ params.data.format }}</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
params: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
16
app/javascript/vue/label_template/renderers/name.vue
Normal file
16
app/javascript/vue/label_template/renderers/name.vue
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<template>
|
||||||
|
<a :href="params.data.urls.show" :title="params.data.name">
|
||||||
|
{{ params.data.name }}
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
params: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -30,28 +30,34 @@ import axios from '../../packs/custom_axios.js';
|
||||||
|
|
||||||
import DataTable from '../shared/datatable/table.vue';
|
import DataTable from '../shared/datatable/table.vue';
|
||||||
import DeleteModal from '../shared/confirmation_modal.vue';
|
import DeleteModal from '../shared/confirmation_modal.vue';
|
||||||
|
import NameRenderer from './renderers/name.vue';
|
||||||
|
import DefaultRenderer from './renderers/default.vue';
|
||||||
|
import FormatRenderer from './renderers/format.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'LabelTemplatesTable',
|
name: 'LabelTemplatesTable',
|
||||||
components: {
|
components: {
|
||||||
DataTable,
|
DataTable,
|
||||||
DeleteModal,
|
DeleteModal,
|
||||||
|
NameRenderer,
|
||||||
|
DefaultRenderer,
|
||||||
|
FormatRenderer
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
dataSource: {
|
dataSource: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
actionsUrl: {
|
actionsUrl: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true
|
||||||
},
|
},
|
||||||
createUrl: {
|
createUrl: {
|
||||||
type: String,
|
type: String
|
||||||
},
|
},
|
||||||
syncFluicsUrl: {
|
syncFluicsUrl: {
|
||||||
type: String,
|
type: String
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -60,40 +66,40 @@ export default {
|
||||||
{
|
{
|
||||||
field: 'default',
|
field: 'default',
|
||||||
headerName: this.i18n.t('label_templates.index.default_label'),
|
headerName: this.i18n.t('label_templates.index.default_label'),
|
||||||
cellRenderer: this.defaultRenderer,
|
cellRenderer: 'DefaultRenderer',
|
||||||
sortable: true,
|
sortable: true
|
||||||
}, {
|
}, {
|
||||||
field: 'name',
|
field: 'name',
|
||||||
headerName: this.i18n.t('label_templates.index.thead_name'),
|
headerName: this.i18n.t('label_templates.index.thead_name'),
|
||||||
cellRenderer: this.labelNameRenderer,
|
cellRenderer: 'NameRenderer',
|
||||||
sortable: true,
|
sortable: true
|
||||||
}, {
|
}, {
|
||||||
field: 'format',
|
field: 'format',
|
||||||
headerName: this.i18n.t('label_templates.index.format'),
|
headerName: this.i18n.t('label_templates.index.format'),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
cellRenderer: ({ data: { format, icon_url: iconUrl } }) => `<span>${iconUrl}</span> <span>${format}</span>`
|
cellRenderer: 'FormatRenderer'
|
||||||
}, {
|
}, {
|
||||||
field: 'description',
|
field: 'description',
|
||||||
headerName: this.i18n.t('label_templates.index.description'),
|
headerName: this.i18n.t('label_templates.index.description'),
|
||||||
sortable: true,
|
sortable: true
|
||||||
}, {
|
}, {
|
||||||
field: 'modified_by',
|
field: 'modified_by',
|
||||||
headerName: this.i18n.t('label_templates.index.updated_by'),
|
headerName: this.i18n.t('label_templates.index.updated_by'),
|
||||||
sortable: true,
|
sortable: true
|
||||||
}, {
|
}, {
|
||||||
field: 'updated_at',
|
field: 'updated_at',
|
||||||
headerName: this.i18n.t('label_templates.index.updated_at'),
|
headerName: this.i18n.t('label_templates.index.updated_at'),
|
||||||
sortable: true,
|
sortable: true
|
||||||
}, {
|
}, {
|
||||||
field: 'created_by',
|
field: 'created_by',
|
||||||
headerName: this.i18n.t('label_templates.index.created_by'),
|
headerName: this.i18n.t('label_templates.index.created_by'),
|
||||||
sortable: true,
|
sortable: true
|
||||||
}, {
|
}, {
|
||||||
field: 'created_at',
|
field: 'created_at',
|
||||||
headerName: this.i18n.t('label_templates.index.created_at'),
|
headerName: this.i18n.t('label_templates.index.created_at'),
|
||||||
sortable: true,
|
sortable: true
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -106,7 +112,7 @@ export default {
|
||||||
label: this.i18n.t('label_templates.index.toolbar.new'),
|
label: this.i18n.t('label_templates.index.toolbar.new'),
|
||||||
type: 'emit',
|
type: 'emit',
|
||||||
path: this.createUrl,
|
path: this.createUrl,
|
||||||
buttonStyle: 'btn btn-primary',
|
buttonStyle: 'btn btn-primary'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (this.syncFluicsUrl) {
|
if (this.syncFluicsUrl) {
|
||||||
|
|
@ -121,21 +127,11 @@ export default {
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
left,
|
left,
|
||||||
right: [],
|
right: []
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
labelNameRenderer(params) {
|
|
||||||
const editUrl = params.data.urls.show;
|
|
||||||
return `<a href="${editUrl}" title="${params.data.name}">
|
|
||||||
${params.data.name}
|
|
||||||
</a>`;
|
|
||||||
},
|
|
||||||
defaultRenderer(params) {
|
|
||||||
const defaultSelected = params.data.default;
|
|
||||||
return defaultSelected ? '<i class="sn-icon sn-icon-approval"></i>' : '';
|
|
||||||
},
|
|
||||||
setDefault(action) {
|
setDefault(action) {
|
||||||
axios.post(action.path).then((response) => {
|
axios.post(action.path).then((response) => {
|
||||||
this.reloadingTable = true;
|
this.reloadingTable = true;
|
||||||
|
|
@ -175,8 +171,8 @@ export default {
|
||||||
HelperModule.flashAlertMsg(error.response.data.error, 'danger');
|
HelperModule.flashAlertMsg(error.response.data.error, 'danger');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
:hiddenDataMessage="i18n.t('experiments.empty_state.no_active_modules_archived_branch')"
|
:hiddenDataMessage="i18n.t('experiments.empty_state.no_active_modules_archived_branch')"
|
||||||
scrollMode="infinite"
|
scrollMode="infinite"
|
||||||
@tableReloaded="reloadingTable = false"
|
@tableReloaded="reloadingTable = false"
|
||||||
|
@reloadTable="reloadingTable = true"
|
||||||
@create="newModalOpen = true"
|
@create="newModalOpen = true"
|
||||||
@edit="edit"
|
@edit="edit"
|
||||||
@move="move"
|
@move="move"
|
||||||
|
|
@ -56,6 +57,9 @@
|
||||||
import axios from '../../packs/custom_axios.js';
|
import axios from '../../packs/custom_axios.js';
|
||||||
import DataTable from '../shared/datatable/table.vue';
|
import DataTable from '../shared/datatable/table.vue';
|
||||||
import ConfirmationModal from '../shared/confirmation_modal.vue';
|
import ConfirmationModal from '../shared/confirmation_modal.vue';
|
||||||
|
import NameRenderer from './renderers/name.vue';
|
||||||
|
import ResultsRenderer from './renderers/results.vue';
|
||||||
|
import StatusRenderer from './renderers/status.vue';
|
||||||
import DueDateRenderer from './renderers/due_date.vue';
|
import DueDateRenderer from './renderers/due_date.vue';
|
||||||
import DesignatedUsers from './renderers/designated_users.vue';
|
import DesignatedUsers from './renderers/designated_users.vue';
|
||||||
import TagsModal from './modals/tags.vue';
|
import TagsModal from './modals/tags.vue';
|
||||||
|
|
@ -77,7 +81,10 @@ export default {
|
||||||
NewModal,
|
NewModal,
|
||||||
EditModal,
|
EditModal,
|
||||||
MoveModal,
|
MoveModal,
|
||||||
AccessModal
|
AccessModal,
|
||||||
|
NameRenderer,
|
||||||
|
ResultsRenderer,
|
||||||
|
StatusRenderer
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
dataSource: { type: String, required: true },
|
dataSource: { type: String, required: true },
|
||||||
|
|
@ -115,7 +122,7 @@ export default {
|
||||||
field: 'name',
|
field: 'name',
|
||||||
headerName: this.i18n.t('experiments.table.column.task_name_html'),
|
headerName: this.i18n.t('experiments.table.column.task_name_html'),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
cellRenderer: this.nameRenderer
|
cellRenderer: NameRenderer
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'code',
|
field: 'code',
|
||||||
|
|
@ -133,7 +140,7 @@ export default {
|
||||||
field: 'results',
|
field: 'results',
|
||||||
headerName: this.i18n.t('experiments.table.column.results_html'),
|
headerName: this.i18n.t('experiments.table.column.results_html'),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
cellRenderer: this.resultsRenderer
|
cellRenderer: ResultsRenderer
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'age',
|
field: 'age',
|
||||||
|
|
@ -144,7 +151,7 @@ export default {
|
||||||
field: 'status',
|
field: 'status',
|
||||||
headerName: this.i18n.t('experiments.table.column.status_html'),
|
headerName: this.i18n.t('experiments.table.column.status_html'),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
cellRenderer: this.statusRenderer,
|
cellRenderer: StatusRenderer,
|
||||||
minWidth: 120
|
minWidth: 120
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
@ -321,53 +328,6 @@ export default {
|
||||||
roles_path: this.userRolesUrl
|
roles_path: this.userRolesUrl
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
checkProvisioning(params) {
|
|
||||||
if (params.data.provisioning_status === 'done') return;
|
|
||||||
|
|
||||||
axios.get(params.data.urls.provisioning_status).then((response) => {
|
|
||||||
const provisioningStatus = response.data.provisioning_status;
|
|
||||||
if (provisioningStatus === 'done') {
|
|
||||||
this.reloadingTable = true;
|
|
||||||
} else {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.checkProvisioning(params);
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// Renderers
|
|
||||||
nameRenderer(params) {
|
|
||||||
const { name, urls } = params.data;
|
|
||||||
const provisioningStatus = params.data.provisioning_status;
|
|
||||||
if (provisioningStatus === 'in_progress') {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.checkProvisioning(params);
|
|
||||||
}, 5000);
|
|
||||||
return `
|
|
||||||
<span class="flex gap-2 items-center">
|
|
||||||
<div title="${this.i18n.t('experiments.duplicate_tasks.duplicating')}"
|
|
||||||
class="loading-overlay w-6 h-6 !relative shrink-0" data-toggle="tooltip" data-placement="right"></div>
|
|
||||||
<span class="truncate">${name}</span>
|
|
||||||
</span>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `<a href="${urls.show}" title="${name}" ><span class="truncate">${name}</span></a>`;
|
|
||||||
},
|
|
||||||
statusRenderer(params) {
|
|
||||||
const { status } = params.data;
|
|
||||||
|
|
||||||
return `<span
|
|
||||||
class="px-2 py-1 border border-solid rounded truncate ${!status.light_color ? 'text-sn-white' : ''}"
|
|
||||||
style="background-color: ${status.color};"
|
|
||||||
>
|
|
||||||
${status.name}
|
|
||||||
</span>`;
|
|
||||||
},
|
|
||||||
resultsRenderer(params) {
|
|
||||||
const { results, urls } = params.data;
|
|
||||||
|
|
||||||
return `<a href="${urls.results}" >${results}</a>`;
|
|
||||||
},
|
|
||||||
usersFilterRenderer(option) {
|
usersFilterRenderer(option) {
|
||||||
return `<div class="flex items-center gap-2">
|
return `<div class="flex items-center gap-2">
|
||||||
<img src="${option[2].avatar_url}" class="rounded-full w-6 h-6" />
|
<img src="${option[2].avatar_url}" class="rounded-full w-6 h-6" />
|
||||||
|
|
|
||||||
50
app/javascript/vue/my_modules/renderers/name.vue
Normal file
50
app/javascript/vue/my_modules/renderers/name.vue
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
<template>
|
||||||
|
<template v-if="params.data.provisioning_status === 'in_progress'">
|
||||||
|
<span class="flex gap-2 items-center">
|
||||||
|
<div :title="this.i18n.t('experiments.duplicate_tasks.duplicating')"
|
||||||
|
class="loading-overlay w-6 h-6 !relative shrink-0" data-toggle="tooltip" data-placement="right"></div>
|
||||||
|
<span class="truncate">{{ params.data.name }}</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<a :href="params.data.urls.show" :title="params.data.name" >
|
||||||
|
<i v-if="params.data.locked" class="sn-icon sn-icon-locked-task"></i>
|
||||||
|
<span class="truncate">{{ params.data.name }}</span>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from '../../../packs/custom_axios.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'NameRenderer',
|
||||||
|
props: {
|
||||||
|
params: {
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (this.params.data.provisioning_status === 'in_progress') {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.checkProvisioning();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
checkProvisioning() {
|
||||||
|
if (this.params.data.provisioning_status === 'done') return;
|
||||||
|
axios.get(this.params.data.urls.provisioning_status).then((response) => {
|
||||||
|
const provisioningStatus = response.data.provisioning_status;
|
||||||
|
if (provisioningStatus === 'done') {
|
||||||
|
this.params.dtComponent.$emit('reloadTable', null, [this.params.data]);
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.checkProvisioning();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
14
app/javascript/vue/my_modules/renderers/results.vue
Normal file
14
app/javascript/vue/my_modules/renderers/results.vue
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<template>
|
||||||
|
<a :href="params.data.urls.results" >{{ params.data.results }}</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ResultsRenderer',
|
||||||
|
props: {
|
||||||
|
params: {
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
20
app/javascript/vue/my_modules/renderers/status.vue
Normal file
20
app/javascript/vue/my_modules/renderers/status.vue
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
<template>
|
||||||
|
<span
|
||||||
|
class="px-2 py-1 border border-solid rounded truncate"
|
||||||
|
:class="{'text-sn-white' : !params.data.status.light_color}"
|
||||||
|
:style="{'background-color': params.data.status.color}"
|
||||||
|
>
|
||||||
|
{{ params.data.status.name }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'StatusRenderer',
|
||||||
|
props: {
|
||||||
|
params: {
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -68,6 +68,7 @@ import axios from '../../packs/custom_axios.js';
|
||||||
|
|
||||||
import DataTable from '../shared/datatable/table.vue';
|
import DataTable from '../shared/datatable/table.vue';
|
||||||
import UsersRenderer from './renderers/users.vue';
|
import UsersRenderer from './renderers/users.vue';
|
||||||
|
import NameRenderer from './renderers/name.vue';
|
||||||
import CommentsRenderer from '../shared/datatable/renderers/comments.vue';
|
import CommentsRenderer from '../shared/datatable/renderers/comments.vue';
|
||||||
import ProjectCard from './card.vue';
|
import ProjectCard from './card.vue';
|
||||||
import ConfirmationModal from '../shared/confirmation_modal.vue';
|
import ConfirmationModal from '../shared/confirmation_modal.vue';
|
||||||
|
|
@ -84,6 +85,7 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
DataTable,
|
DataTable,
|
||||||
UsersRenderer,
|
UsersRenderer,
|
||||||
|
NameRenderer,
|
||||||
ProjectCard,
|
ProjectCard,
|
||||||
ConfirmationModal,
|
ConfirmationModal,
|
||||||
EditProjectModal,
|
EditProjectModal,
|
||||||
|
|
@ -129,7 +131,7 @@ export default {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
headerName: this.i18n.t('projects.index.card.name'),
|
headerName: this.i18n.t('projects.index.card.name'),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
cellRenderer: this.nameRenderer
|
cellRenderer: 'NameRenderer'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'code',
|
field: 'code',
|
||||||
|
|
@ -252,16 +254,6 @@ export default {
|
||||||
<span title="${option[1]}" class="truncate">${option[1]}</span>
|
<span title="${option[1]}" class="truncate">${option[1]}</span>
|
||||||
</div>`;
|
</div>`;
|
||||||
},
|
},
|
||||||
nameRenderer(params) {
|
|
||||||
const showUrl = params.data.urls.show;
|
|
||||||
return `<a href="${showUrl}"
|
|
||||||
class="flex items-center gap-1 hover:no-underline
|
|
||||||
${!showUrl ? 'pointer-events-none text-sn-grey' : ''}"
|
|
||||||
title="${params.data.name}">
|
|
||||||
${params.data.folder ? '<i class="sn-icon mini sn-icon-mini-folder-left"></i>' : ''}
|
|
||||||
<span class="truncate">${params.data.name} </span>
|
|
||||||
</a>`;
|
|
||||||
},
|
|
||||||
openComments(_params, rows) {
|
openComments(_params, rows) {
|
||||||
$(this.$refs.commentButton).data('objectId', rows[0].id);
|
$(this.$refs.commentButton).data('objectId', rows[0].id);
|
||||||
this.$refs.commentButton.click();
|
this.$refs.commentButton.click();
|
||||||
|
|
|
||||||
21
app/javascript/vue/projects/renderers/name.vue
Normal file
21
app/javascript/vue/projects/renderers/name.vue
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<template>
|
||||||
|
<a :href="params.data.urls.show"
|
||||||
|
class="flex items-center gap-1 hover:no-underline"
|
||||||
|
:class="{
|
||||||
|
'pointer-events-none text-sn-grey': !params.data.urls.show
|
||||||
|
}"
|
||||||
|
:title="params.data.name">
|
||||||
|
<i v-if="params.data.folder" class="sn-icon mini sn-icon-mini-folder-left"></i>
|
||||||
|
<span class="truncate">{{ params.data.name }}</span>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'NameRenderer',
|
||||||
|
props: {
|
||||||
|
params: {
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -19,8 +19,8 @@ export default {
|
||||||
name: 'UsersRenderer',
|
name: 'UsersRenderer',
|
||||||
props: {
|
props: {
|
||||||
params: {
|
params: {
|
||||||
required: true,
|
required: true
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
users() {
|
users() {
|
||||||
|
|
|
||||||
21
app/javascript/vue/protocols/renderers/name.vue
Normal file
21
app/javascript/vue/protocols/renderers/name.vue
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<template>
|
||||||
|
<a v-if="params.data.urls.show"
|
||||||
|
:href="params.data.urls.show"
|
||||||
|
:title="params.data.name">
|
||||||
|
{{ params.data.name }}
|
||||||
|
</a>
|
||||||
|
<span v-else class="text-sn-grey" :title="params.data.name">
|
||||||
|
{{ params.data.name }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
params: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -42,6 +42,7 @@ import axios from '../../packs/custom_axios.js';
|
||||||
|
|
||||||
import DataTable from '../shared/datatable/table.vue';
|
import DataTable from '../shared/datatable/table.vue';
|
||||||
import UsersRenderer from '../projects/renderers/users.vue';
|
import UsersRenderer from '../projects/renderers/users.vue';
|
||||||
|
import NameRenderer from './renderers/name.vue';
|
||||||
import NewProtocolModal from './modals/new.vue';
|
import NewProtocolModal from './modals/new.vue';
|
||||||
import AccessModal from '../shared/access_modal/modal.vue';
|
import AccessModal from '../shared/access_modal/modal.vue';
|
||||||
import KeywordsRenderer from './renderers/keywords.vue';
|
import KeywordsRenderer from './renderers/keywords.vue';
|
||||||
|
|
@ -55,6 +56,7 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
DataTable,
|
DataTable,
|
||||||
UsersRenderer,
|
UsersRenderer,
|
||||||
|
NameRenderer,
|
||||||
NewProtocolModal,
|
NewProtocolModal,
|
||||||
AccessModal,
|
AccessModal,
|
||||||
KeywordsRenderer,
|
KeywordsRenderer,
|
||||||
|
|
@ -116,7 +118,7 @@ export default {
|
||||||
headerName: this.i18n.t('protocols.index.thead.name'),
|
headerName: this.i18n.t('protocols.index.thead.name'),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
notSelectable: true,
|
notSelectable: true,
|
||||||
cellRenderer: this.nameRenderer
|
cellRenderer: 'NameRenderer'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'code',
|
field: 'code',
|
||||||
|
|
@ -337,14 +339,6 @@ export default {
|
||||||
linkedMyModules(_event, rows) {
|
linkedMyModules(_event, rows) {
|
||||||
[this.linkedMyModulesModalObject] = rows;
|
[this.linkedMyModulesModalObject] = rows;
|
||||||
},
|
},
|
||||||
// renderers
|
|
||||||
nameRenderer(params) {
|
|
||||||
const { urls, name } = params.data;
|
|
||||||
if (urls.show) {
|
|
||||||
return `<a href="${urls.show}" title="${name}">${name}</a>`;
|
|
||||||
}
|
|
||||||
return `<span class="text-sn-grey" title="${name}">${name}</span>`;
|
|
||||||
},
|
|
||||||
usersFilterRenderer(option) {
|
usersFilterRenderer(option) {
|
||||||
return `<div class="flex items-center gap-2">
|
return `<div class="flex items-center gap-2">
|
||||||
<img src="${option[2].avatar_url}" class="rounded-full w-6 h-6" />
|
<img src="${option[2].avatar_url}" class="rounded-full w-6 h-6" />
|
||||||
|
|
|
||||||
16
app/javascript/vue/reports/renderers/name.vue
Normal file
16
app/javascript/vue/reports/renderers/name.vue
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<template>
|
||||||
|
<span :title="params.data.name">
|
||||||
|
{{ params.data.name }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
params: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -43,6 +43,7 @@ import axios from '../../packs/custom_axios.js';
|
||||||
import DataTable from '../shared/datatable/table.vue';
|
import DataTable from '../shared/datatable/table.vue';
|
||||||
import DocxRenderer from './renderers/docx.vue';
|
import DocxRenderer from './renderers/docx.vue';
|
||||||
import PdfRenderer from './renderers/pdf.vue';
|
import PdfRenderer from './renderers/pdf.vue';
|
||||||
|
import NameRenderer from './renderers/name.vue';
|
||||||
import ConfirmationModal from '../shared/confirmation_modal.vue';
|
import ConfirmationModal from '../shared/confirmation_modal.vue';
|
||||||
import SaveToInventoryModal from './modals/save_to_inventory.vue';
|
import SaveToInventoryModal from './modals/save_to_inventory.vue';
|
||||||
import UpdateReportModal from './modals/update.vue';
|
import UpdateReportModal from './modals/update.vue';
|
||||||
|
|
@ -60,6 +61,7 @@ export default {
|
||||||
DataTable,
|
DataTable,
|
||||||
DocxRenderer,
|
DocxRenderer,
|
||||||
PdfRenderer,
|
PdfRenderer,
|
||||||
|
NameRenderer,
|
||||||
ConfirmationModal,
|
ConfirmationModal,
|
||||||
SaveToInventoryModal,
|
SaveToInventoryModal,
|
||||||
UpdateReportModal
|
UpdateReportModal
|
||||||
|
|
@ -108,7 +110,7 @@ export default {
|
||||||
field: 'name',
|
field: 'name',
|
||||||
headerName: this.i18n.t('projects.reports.index.thead_name'),
|
headerName: this.i18n.t('projects.reports.index.thead_name'),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
cellRenderer: ({ data: { name } }) => `<span title="${name}">${name}</span>`
|
cellRenderer: 'NameRenderer'
|
||||||
}, {
|
}, {
|
||||||
field: 'code',
|
field: 'code',
|
||||||
headerName: this.i18n.t('projects.reports.index.thead_id'),
|
headerName: this.i18n.t('projects.reports.index.thead_id'),
|
||||||
|
|
|
||||||
22
app/javascript/vue/repositories/renderers/name.vue
Normal file
22
app/javascript/vue/repositories/renderers/name.vue
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<template>
|
||||||
|
<a class="hover:no-underline flex items-center gap-1"
|
||||||
|
:title="params.data.name"
|
||||||
|
:href="params.data.urls.show"
|
||||||
|
>
|
||||||
|
<span class="truncate">
|
||||||
|
<i v-if="params.data.shared || params.data.ishared" class="fas fa-users"></i>
|
||||||
|
{{ params.data.name }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
params: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -68,6 +68,7 @@ import EditRepositoryModal from './modals/edit.vue';
|
||||||
import DuplicateRepositoryModal from './modals/duplicate.vue';
|
import DuplicateRepositoryModal from './modals/duplicate.vue';
|
||||||
import ShareRepositoryModal from './modals/share.vue';
|
import ShareRepositoryModal from './modals/share.vue';
|
||||||
import DataTable from '../shared/datatable/table.vue';
|
import DataTable from '../shared/datatable/table.vue';
|
||||||
|
import NameRenderer from './renderers/name.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RepositoriesTable',
|
name: 'RepositoriesTable',
|
||||||
|
|
@ -78,7 +79,8 @@ export default {
|
||||||
NewRepositoryModal,
|
NewRepositoryModal,
|
||||||
EditRepositoryModal,
|
EditRepositoryModal,
|
||||||
DuplicateRepositoryModal,
|
DuplicateRepositoryModal,
|
||||||
ShareRepositoryModal
|
ShareRepositoryModal,
|
||||||
|
NameRenderer
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
dataSource: {
|
dataSource: {
|
||||||
|
|
@ -138,7 +140,7 @@ export default {
|
||||||
headerName: this.i18n.t('libraries.index.table.name'),
|
headerName: this.i18n.t('libraries.index.table.name'),
|
||||||
sortable: true,
|
sortable: true,
|
||||||
notSelectable: true,
|
notSelectable: true,
|
||||||
cellRenderer: this.nameRenderer
|
cellRenderer: 'NameRenderer'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'code',
|
field: 'code',
|
||||||
|
|
@ -277,23 +279,6 @@ export default {
|
||||||
share(_event, rows) {
|
share(_event, rows) {
|
||||||
const [repository] = rows;
|
const [repository] = rows;
|
||||||
this.shareRepository = repository;
|
this.shareRepository = repository;
|
||||||
},
|
|
||||||
// Renderers
|
|
||||||
nameRenderer(params) {
|
|
||||||
const {
|
|
||||||
name,
|
|
||||||
urls,
|
|
||||||
shared,
|
|
||||||
ishared
|
|
||||||
} = params.data;
|
|
||||||
let sharedIcon = '';
|
|
||||||
if (shared || ishared) {
|
|
||||||
sharedIcon = '<i class="fas fa-users"></i>';
|
|
||||||
}
|
|
||||||
return `<a class="hover:no-underline flex items-center gap-1"
|
|
||||||
title="${name}" href="${urls.show}">
|
|
||||||
<span class="truncate">${sharedIcon}${name}</span>
|
|
||||||
</a>`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
|
/* global GLOBAL_CONSTANTS */
|
||||||
|
|
||||||
import axios from '../../../../../packs/custom_axios.js';
|
import axios from '../../../../../packs/custom_axios.js';
|
||||||
import { satisfies } from 'compare-versions';
|
import { satisfies } from 'compare-versions';
|
||||||
import editLaunchingApplicationModal from '../../modal/edit_launching_application_modal.vue';
|
import editLaunchingApplicationModal from '../../modal/edit_launching_application_modal.vue';
|
||||||
import NoPredefinedAppModal from '../../modal/no_predefined_app_modal.vue';
|
import NoPredefinedAppModal from '../../modal/no_predefined_app_modal.vue';
|
||||||
|
import RestrictedExtensionModal from '../../modal/restricted_extension_modal.vue';
|
||||||
import UpdateVersionModal from '../../modal/update_version_modal.vue';
|
import UpdateVersionModal from '../../modal/update_version_modal.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -10,15 +13,17 @@ export default {
|
||||||
localAppName: null,
|
localAppName: null,
|
||||||
scinoteEditRunning: null,
|
scinoteEditRunning: null,
|
||||||
showNoPredefinedAppModal: false,
|
showNoPredefinedAppModal: false,
|
||||||
|
showRestrictedExtensionModal: false,
|
||||||
showUpdateVersionModal: false,
|
showUpdateVersionModal: false,
|
||||||
editAppModal: false,
|
editAppModal: false,
|
||||||
pollingInterval: null,
|
pollingInterval: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
editLaunchingApplicationModal,
|
editLaunchingApplicationModal,
|
||||||
NoPredefinedAppModal,
|
NoPredefinedAppModal,
|
||||||
UpdateVersionModal
|
UpdateVersionModal,
|
||||||
|
RestrictedExtensionModal
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
attributes() {
|
attributes() {
|
||||||
|
|
@ -93,9 +98,16 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async openLocally() {
|
async openLocally() {
|
||||||
|
const restrictedExtension = GLOBAL_CONSTANTS.SCINOTE_EDIT_RESTRICTED_EXTENSIONS.includes(
|
||||||
|
this.attributes.file_extension.toUpperCase()
|
||||||
|
);
|
||||||
|
|
||||||
if (this.isWrongVersion(window.scinoteEditVersion)) {
|
if (this.isWrongVersion(window.scinoteEditVersion)) {
|
||||||
this.showUpdateVersionModal = true;
|
this.showUpdateVersionModal = true;
|
||||||
return;
|
return;
|
||||||
|
} else if (restrictedExtension) {
|
||||||
|
this.showRestrictedExtensionModal = true;
|
||||||
|
return;
|
||||||
} else if (this.localAppName === null) {
|
} else if (this.localAppName === null) {
|
||||||
this.showNoPredefinedAppModal = true;
|
this.showNoPredefinedAppModal = true;
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,10 @@
|
||||||
:fileName="attachment.attributes.file_name"
|
:fileName="attachment.attributes.file_name"
|
||||||
@close="showNoPredefinedAppModal = false"
|
@close="showNoPredefinedAppModal = false"
|
||||||
/>
|
/>
|
||||||
|
<RestrictedExtensionModal
|
||||||
|
v-if="showRestrictedExtensionModal"
|
||||||
|
@close="showRestrictedExtensionModal = false"
|
||||||
|
/>
|
||||||
<editLaunchingApplicationModal
|
<editLaunchingApplicationModal
|
||||||
v-if="editAppModal"
|
v-if="editAppModal"
|
||||||
:fileName="attachment.attributes.file_name"
|
:fileName="attachment.attributes.file_name"
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,10 @@
|
||||||
:fileName="attachment.attributes.file_name"
|
:fileName="attachment.attributes.file_name"
|
||||||
@close="showNoPredefinedAppModal = false"
|
@close="showNoPredefinedAppModal = false"
|
||||||
/>
|
/>
|
||||||
|
<RestrictedExtensionModal
|
||||||
|
v-if="showRestrictedExtensionModal"
|
||||||
|
@close="showRestrictedExtensionModal = false"
|
||||||
|
/>
|
||||||
<UpdateVersionModal
|
<UpdateVersionModal
|
||||||
v-if="showUpdateVersionModal"
|
v-if="showUpdateVersionModal"
|
||||||
@close="showUpdateVersionModal = false"
|
@close="showUpdateVersionModal = false"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<template>
|
||||||
|
<div ref="modal" @keydown.esc="cancel" class="modal" id="RestrictedExtensionModal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog modal-md" role="document">
|
||||||
|
<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" id="modal-delete-result-element">
|
||||||
|
{{ i18n.t('assets.restricted_extension_modal.title') }}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p v-html="i18n.t('assets.restricted_extension_modal.body')"></p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn btn-primary" @click="close">{{ this.i18n.t('assets.restricted_extension_modal.action') }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import modalMixin from '../../modal_mixin';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'RestrictedExtensionModal',
|
||||||
|
mixins: [modalMixin]
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -447,6 +447,12 @@ class Constants
|
||||||
MIN_SCINOTE_EDIT_VERSION = ENV['MIN_SCINOTE_EDIT_VERSION'].freeze
|
MIN_SCINOTE_EDIT_VERSION = ENV['MIN_SCINOTE_EDIT_VERSION'].freeze
|
||||||
MAX_SCINOTE_EDIT_VERSION = ENV['MAX_SCINOTE_EDIT_VERSION'].freeze
|
MAX_SCINOTE_EDIT_VERSION = ENV['MAX_SCINOTE_EDIT_VERSION'].freeze
|
||||||
|
|
||||||
|
# SciNote Edit unsupported extensions
|
||||||
|
SCINOTE_EDIT_RESTRICTED_EXTENSIONS = %w(
|
||||||
|
ACTION APP BIN COMMAND CSH OSX WORKFLOW DMG BAT BIN CAB CMD COM CPL EX_ EXE GADGET INF1 INS INX ISU JOB
|
||||||
|
JSE LNK MSC MSI MSP MST PAF PIF PS1 REG RGS SCR SCT SHB SHS U3P VB VBE VBS VBSCRIPT WS WSF WSH
|
||||||
|
).freeze
|
||||||
|
|
||||||
# quick search
|
# quick search
|
||||||
QUICK_SEARCH_LIMIT = 5
|
QUICK_SEARCH_LIMIT = 5
|
||||||
QUICK_SEARCH_SEARCHABLE_OBJECTS = %w(project experiment my_module protocol repository_row
|
QUICK_SEARCH_SEARCHABLE_OBJECTS = %w(project experiment my_module protocol repository_row
|
||||||
|
|
|
||||||
|
|
@ -3907,6 +3907,10 @@ en:
|
||||||
body_text_html: "The specified application for accessing the <b>%{file_name}</b> is not preconfigured. To successfully open this file, please set up the appropriate application in your local environment beforehand.</p>"
|
body_text_html: "The specified application for accessing the <b>%{file_name}</b> is not preconfigured. To successfully open this file, please set up the appropriate application in your local environment beforehand.</p>"
|
||||||
understand_button: "I understand"
|
understand_button: "I understand"
|
||||||
set_up_app: "Set up an application to open this file"
|
set_up_app: "Set up an application to open this file"
|
||||||
|
restricted_extension_modal:
|
||||||
|
title: "Open file - Security warning"
|
||||||
|
body: "This file type appears to be executable and can potentially harm your computer. It cannot be opened with SciNote Edit. To open the file please download it manually."
|
||||||
|
action: "I understand"
|
||||||
update_version_modal:
|
update_version_modal:
|
||||||
title: "Update required"
|
title: "Update required"
|
||||||
body_text_html: "The current version of the SciNote Edit application is no longer supported. To ensure a seamless and secure user experience, we recommend updating to the latest version."
|
body_text_html: "The current version of the SciNote Edit application is no longer supported. To ensure a seamless and secure user experience, we recommend updating to the latest version."
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue