mirror of
https://github.com/jumpserver/lina.git
synced 2025-11-08 02:18:44 +00:00
Compare commits
3 Commits
pr@v3@fixe
...
v2.11.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48beb502bd | ||
|
|
383a799c6a | ||
|
|
c378b2bf0d |
@@ -23,10 +23,10 @@ export default {
|
|||||||
actions: {
|
actions: {
|
||||||
formatterArgs: {
|
formatterArgs: {
|
||||||
canClone: true,
|
canClone: true,
|
||||||
canDelete: (row, value) => {
|
canDelete: ({ row }) => {
|
||||||
return !row.internal
|
return !row.internal
|
||||||
},
|
},
|
||||||
canUpdate: (row, value) => {
|
canUpdate: ({ row }) => {
|
||||||
return !row.internal
|
return !row.internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import ListTable from '@/components/ListTable'
|
|||||||
import { OutputExpandFormatter } from '../formatters'
|
import { OutputExpandFormatter } from '../formatters'
|
||||||
import { toSafeLocalDateStr } from '@/utils/common'
|
import { toSafeLocalDateStr } from '@/utils/common'
|
||||||
export default {
|
export default {
|
||||||
name: 'SessionCommandList',
|
name: 'SessionCommands',
|
||||||
components: {
|
components: {
|
||||||
ListTable
|
ListTable
|
||||||
},
|
},
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
<template>
|
|
||||||
<el-row :gutter="20">
|
|
||||||
<el-col :span="14">
|
|
||||||
<DetailCard :items="detailItems" />
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="10">
|
|
||||||
<QuickActions type="primary" :actions="quickActions" />
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import DetailCard from '@/components/DetailCard/index'
|
|
||||||
import QuickActions from '@/components/QuickActions'
|
|
||||||
import { terminateSession } from '@/api/sessions'
|
|
||||||
import { toSafeLocalDateStr } from '@/utils/common'
|
|
||||||
export default {
|
|
||||||
name: 'SessionDetailCard',
|
|
||||||
components: {
|
|
||||||
DetailCard,
|
|
||||||
QuickActions
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
object: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
sessionData: this.object
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
detailItems() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
key: this.$t('sessions.user'),
|
|
||||||
value: this.sessionData.user
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('sessions.asset'),
|
|
||||||
value: this.sessionData.asset
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('sessions.systemUser'),
|
|
||||||
value: this.sessionData.system_user
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('sessions.protocol'),
|
|
||||||
value: this.sessionData.protocol
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('sessions.loginFrom'),
|
|
||||||
value: this.sessionData.login_from
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('sessions.remoteAddr'),
|
|
||||||
value: this.sessionData.remote_addr
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('sessions.dateStart'),
|
|
||||||
value: toSafeLocalDateStr(this.sessionData.date_start)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: this.$t('sessions.dateEnd'),
|
|
||||||
value: this.sessionData.date_end ? toSafeLocalDateStr(this.sessionData.date_end) : ''
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
quickActions() {
|
|
||||||
const vm = this
|
|
||||||
if (vm.sessionData.is_finished) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
title: this.$t('sessions.replaySession'),
|
|
||||||
attrs: {
|
|
||||||
type: 'primary',
|
|
||||||
label: this.$t('sessions.replay')
|
|
||||||
},
|
|
||||||
callbacks: {
|
|
||||||
click: function() {
|
|
||||||
vm.openReplaySession(vm.sessionData.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: this.$t('sessions.downloadReplay'),
|
|
||||||
attrs: {
|
|
||||||
type: 'primary',
|
|
||||||
label: this.$t('sessions.download')
|
|
||||||
},
|
|
||||||
callbacks: {
|
|
||||||
click: function() {
|
|
||||||
vm.openReplayDownload(vm.sessionData.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
} else {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
title: this.$t('sessions.sessionTerminate'),
|
|
||||||
attrs: {
|
|
||||||
type: 'danger',
|
|
||||||
label: this.$t('sessions.terminate'),
|
|
||||||
disabled: !vm.sessionData.can_terminate
|
|
||||||
},
|
|
||||||
callbacks: {
|
|
||||||
click: function() {
|
|
||||||
// 终断 session reload
|
|
||||||
terminateSession(vm.sessionData.id).then(res => {
|
|
||||||
const msg = vm.$t('sessions.TerminateTaskSendSuccessMsg')
|
|
||||||
vm.$message.success(msg)
|
|
||||||
window.setTimeout(function() {
|
|
||||||
window.location.reload()
|
|
||||||
}, 50000)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: this.$t('sessions.sessionMonitor'),
|
|
||||||
attrs: {
|
|
||||||
type: 'primary',
|
|
||||||
label: this.$t('sessions.Monitor'),
|
|
||||||
disabled: !vm.sessionData.can_join
|
|
||||||
},
|
|
||||||
callbacks: {
|
|
||||||
click: function() {
|
|
||||||
// 跳转到luna页面
|
|
||||||
const joinUrl = '/luna/join/?shareroom=' + vm.sessionData.id
|
|
||||||
window.open(joinUrl, 'height=600, width=800, top=400, left=400, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
openReplaySession: function(id) {
|
|
||||||
const replayUrl = '/luna/replay/' + id
|
|
||||||
window.open(replayUrl)
|
|
||||||
},
|
|
||||||
openReplayDownload: function(id) {
|
|
||||||
const downloadUrl = '/api/v1/terminal/sessions/00000000-0000-0000-0000-000000000000/replay/download/'
|
|
||||||
.replace('00000000-0000-0000-0000-000000000000', id)
|
|
||||||
window.open(downloadUrl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
158
src/views/sessions/SessionDetail/SessionDetailInfo.vue
Normal file
158
src/views/sessions/SessionDetail/SessionDetailInfo.vue
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
<template>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="14">
|
||||||
|
<DetailCard v-if="object" :items="detailItems" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="10">
|
||||||
|
<QuickActions v-if="object" type="primary" :actions="quickActions" />
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import DetailCard from '@/components/DetailCard/index'
|
||||||
|
import QuickActions from '@/components/QuickActions'
|
||||||
|
import { terminateSession } from '@/api/sessions'
|
||||||
|
import { toSafeLocalDateStr } from '@/utils/common'
|
||||||
|
export default {
|
||||||
|
name: 'SessionDetailInfo',
|
||||||
|
components: {
|
||||||
|
DetailCard,
|
||||||
|
QuickActions
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
object: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
session: this.object
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
onlineSessionActions() {
|
||||||
|
const vm = this
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: this.$t('sessions.sessionTerminate'),
|
||||||
|
attrs: {
|
||||||
|
type: 'danger',
|
||||||
|
label: this.$t('sessions.terminate'),
|
||||||
|
disabled: !this.session['can_terminate']
|
||||||
|
},
|
||||||
|
callbacks: {
|
||||||
|
click: function() {
|
||||||
|
// 终断 session reload
|
||||||
|
terminateSession(vm.session.id).then(res => {
|
||||||
|
const msg = vm.$t('sessions.TerminateTaskSendSuccessMsg')
|
||||||
|
vm.$message.success(msg)
|
||||||
|
window.setTimeout(function() {
|
||||||
|
window.location.reload()
|
||||||
|
}, 50000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: this.$t('sessions.sessionMonitor'),
|
||||||
|
attrs: {
|
||||||
|
type: 'primary',
|
||||||
|
label: this.$t('sessions.Monitor'),
|
||||||
|
disabled: !this.session['can_join']
|
||||||
|
},
|
||||||
|
callbacks: {
|
||||||
|
click: function() {
|
||||||
|
// 跳转到luna页面
|
||||||
|
const joinUrl = '/luna/monitor/' + vm.session.id
|
||||||
|
window.open(joinUrl, 'height=600, width=800, top=400, left=400, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
offlineSessionActions() {
|
||||||
|
const vm = this
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: this.$t('sessions.replaySession'),
|
||||||
|
attrs: {
|
||||||
|
type: 'primary',
|
||||||
|
label: this.$t('sessions.replay'),
|
||||||
|
disabled: !this.session['can_replay']
|
||||||
|
},
|
||||||
|
callbacks: {
|
||||||
|
click: function() {
|
||||||
|
const replayUrl = '/luna/replay/' + vm.session.id
|
||||||
|
window.open(replayUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: this.$t('sessions.downloadReplay'),
|
||||||
|
attrs: {
|
||||||
|
type: 'primary',
|
||||||
|
label: this.$t('sessions.download'),
|
||||||
|
disabled: !this.session['can_replay']
|
||||||
|
},
|
||||||
|
callbacks: {
|
||||||
|
click: function() {
|
||||||
|
const downloadUrl = `/api/v1/terminal/sessions/${vm.session.id}/replay/download/`
|
||||||
|
window.open(downloadUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
detailItems() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.user'),
|
||||||
|
value: this.session.user
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.asset'),
|
||||||
|
value: this.session.asset
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.systemUser'),
|
||||||
|
value: this.session.system_user
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.protocol'),
|
||||||
|
value: this.session.protocol
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.loginFrom'),
|
||||||
|
value: this.session.login_from
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.remoteAddr'),
|
||||||
|
value: this.session.remote_addr
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.dateStart'),
|
||||||
|
value: toSafeLocalDateStr(this.session.date_start)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: this.$t('sessions.dateEnd'),
|
||||||
|
value: this.session.date_end ? toSafeLocalDateStr(this.session.date_end) : ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
quickActions() {
|
||||||
|
const vm = this
|
||||||
|
if (vm.session.is_finished) {
|
||||||
|
return this.offlineSessionActions
|
||||||
|
} else {
|
||||||
|
return this.onlineSessionActions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -14,27 +14,27 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { GenericDetailPage } from '@/layout/components'
|
import { GenericDetailPage } from '@/layout/components'
|
||||||
import SessionCommandList from './SessionCommandList'
|
import SessionCommands from './SessionCommands'
|
||||||
import SessionDetailCard from './SessionDetailCard'
|
import SessionDetailInfo from './SessionDetailInfo'
|
||||||
export default {
|
export default {
|
||||||
name: 'SessionDetail',
|
name: 'SessionDetail',
|
||||||
components: {
|
components: {
|
||||||
GenericDetailPage,
|
GenericDetailPage,
|
||||||
SessionCommandList,
|
SessionCommands,
|
||||||
SessionDetailCard
|
SessionDetailInfo
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
sessionData: {},
|
sessionData: {},
|
||||||
activeSubMenu: 'SessionDetailCard',
|
activeSubMenu: 'SessionDetailInfo',
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
title: this.$t('route.SessionDetail'),
|
title: this.$t('route.SessionDetail'),
|
||||||
name: 'SessionDetailCard'
|
name: 'SessionDetailInfo'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: this.$t('sessions.command'),
|
title: this.$t('sessions.command'),
|
||||||
name: 'SessionCommandList'
|
name: 'SessionCommands'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default {
|
|||||||
title: this.$t('sessions.replay'),
|
title: this.$t('sessions.replay'),
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
can: ({ row, cellValue }) => {
|
can: ({ row, cellValue }) => {
|
||||||
return row.can_replay
|
return row['can_replay']
|
||||||
},
|
},
|
||||||
callback: function({ row, tableData }) {
|
callback: function({ row, tableData }) {
|
||||||
// 跳转到luna页面
|
// 跳转到luna页面
|
||||||
@@ -31,7 +31,7 @@ export default {
|
|||||||
title: this.$t('sessions.download'),
|
title: this.$t('sessions.download'),
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
can: ({ row, cellValue }) => {
|
can: ({ row, cellValue }) => {
|
||||||
return row.can_replay
|
return row['can_replay']
|
||||||
},
|
},
|
||||||
callback: function({ row, tableData }) {
|
callback: function({ row, tableData }) {
|
||||||
// 跳转下载页面
|
// 跳转下载页面
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default {
|
|||||||
title: this.$t('sessions.terminate'),
|
title: this.$t('sessions.terminate'),
|
||||||
type: 'danger',
|
type: 'danger',
|
||||||
can: ({ row, cellValue }) => {
|
can: ({ row, cellValue }) => {
|
||||||
return row.can_terminate
|
return row['can_terminate']
|
||||||
},
|
},
|
||||||
callback: function({ reload, row }) {
|
callback: function({ reload, row }) {
|
||||||
// 终断 session reload
|
// 终断 session reload
|
||||||
@@ -40,7 +40,7 @@ export default {
|
|||||||
title: this.$t('sessions.Monitor'),
|
title: this.$t('sessions.Monitor'),
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
can: ({ row, cellValue }) => {
|
can: ({ row, cellValue }) => {
|
||||||
return row.can_join
|
return row['can_join']
|
||||||
},
|
},
|
||||||
tip: ({ row }) => {
|
tip: ({ row }) => {
|
||||||
if (row.login_from === 'RT') {
|
if (row.login_from === 'RT') {
|
||||||
@@ -49,7 +49,7 @@ export default {
|
|||||||
return ''
|
return ''
|
||||||
},
|
},
|
||||||
callback: function({ row, tableData }) {
|
callback: function({ row, tableData }) {
|
||||||
const monitorUrl = '/luna/monitor/' + row.id + '/'
|
const monitorUrl = '/luna/monitor/' + row.id
|
||||||
window.open(monitorUrl, '_blank', 'height=600, width=800, top=400, left=400, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')
|
window.open(monitorUrl, '_blank', 'height=600, width=800, top=400, left=400, toolbar=no, menubar=no, scrollbars=no, location=no, status=no')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,13 +56,13 @@ export default {
|
|||||||
actions: {
|
actions: {
|
||||||
prop: 'id',
|
prop: 'id',
|
||||||
formatterArgs: {
|
formatterArgs: {
|
||||||
canUpdate: function(row, cellValue) {
|
canUpdate: function({ row }) {
|
||||||
return (row.name !== 'default' && row.name !== 'null')
|
return (row.name !== 'default' && row.name !== 'null')
|
||||||
},
|
},
|
||||||
onUpdate: function({ row, col }) {
|
onUpdate: function({ row }) {
|
||||||
this.$router.push({ name: 'CommandStorageUpdate', params: { id: row.id }})
|
this.$router.push({ name: 'CommandStorageUpdate', params: { id: row.id }})
|
||||||
},
|
},
|
||||||
canDelete: function(row, cellValue) {
|
canDelete: function({ row }) {
|
||||||
return (row.name !== 'default' && row.name !== 'null')
|
return (row.name !== 'default' && row.name !== 'null')
|
||||||
},
|
},
|
||||||
extraActions: [
|
extraActions: [
|
||||||
|
|||||||
@@ -67,10 +67,10 @@ export default {
|
|||||||
onUpdate: function({ row, col }) {
|
onUpdate: function({ row, col }) {
|
||||||
this.$router.push({ name: 'ReplayStorageUpdate', params: { id: row.id }, query: { type: row.type }})
|
this.$router.push({ name: 'ReplayStorageUpdate', params: { id: row.id }, query: { type: row.type }})
|
||||||
},
|
},
|
||||||
canUpdate: function(row, cellValue) {
|
canUpdate: function({ row }) {
|
||||||
return (row.name !== 'default' && row.name !== 'null')
|
return (row.name !== 'default' && row.name !== 'null')
|
||||||
},
|
},
|
||||||
canDelete: function(row, cellValue) {
|
canDelete: function({ row }) {
|
||||||
return (row.name !== 'default' && row.name !== 'null')
|
return (row.name !== 'default' && row.name !== 'null')
|
||||||
},
|
},
|
||||||
extraActions: [
|
extraActions: [
|
||||||
|
|||||||
@@ -94,11 +94,17 @@ export default {
|
|||||||
getMethod() {
|
getMethod() {
|
||||||
return 'put'
|
return 'put'
|
||||||
},
|
},
|
||||||
// 不清理的话,编辑secret,在删除提交会报错
|
|
||||||
cleanFormValue(data) {
|
cleanFormValue(data) {
|
||||||
if (!data['EMAIL_HOST_PASSWORD']) {
|
if (!data['EMAIL_HOST_PASSWORD']) {
|
||||||
delete data['EMAIL_HOST_PASSWORD']
|
delete data['EMAIL_HOST_PASSWORD']
|
||||||
}
|
}
|
||||||
|
Object.keys(data).forEach(
|
||||||
|
function(key) {
|
||||||
|
if (data[key] === null) {
|
||||||
|
delete data[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
:fields-meta="fieldsMeta"
|
:fields-meta="fieldsMeta"
|
||||||
:get-method="getMethod"
|
:get-method="getMethod"
|
||||||
:has-detail-in-msg="false"
|
:has-detail-in-msg="false"
|
||||||
|
:clean-form-value="cleanFormValue"
|
||||||
/>
|
/>
|
||||||
</IBox>
|
</IBox>
|
||||||
</template>
|
</template>
|
||||||
@@ -56,9 +57,18 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
getMethod() {
|
getMethod() {
|
||||||
return 'put'
|
return 'put'
|
||||||
|
},
|
||||||
|
cleanFormValue(data) {
|
||||||
|
Object.keys(data).forEach(
|
||||||
|
function(key) {
|
||||||
|
if (data[key] === null) {
|
||||||
|
delete data[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -80,10 +80,10 @@ export default {
|
|||||||
formatterArgs: {
|
formatterArgs: {
|
||||||
canClone: true,
|
canClone: true,
|
||||||
hasDelete: hasDelete,
|
hasDelete: hasDelete,
|
||||||
canUpdate: function(row, cellValue) {
|
canUpdate: function({ row }) {
|
||||||
return row.can_update
|
return row.can_update
|
||||||
},
|
},
|
||||||
canDelete: function(row, cellValue) {
|
canDelete: function({ row }) {
|
||||||
return row.can_delete
|
return row.can_delete
|
||||||
},
|
},
|
||||||
extraActions: [
|
extraActions: [
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export default {
|
|||||||
formatterArgs: {
|
formatterArgs: {
|
||||||
canClone: true,
|
canClone: true,
|
||||||
canUpdate: true,
|
canUpdate: true,
|
||||||
canDelete: function(row, cellValue) {
|
canDelete: function({ row }) {
|
||||||
return !row.is_default
|
return !row.is_default
|
||||||
},
|
},
|
||||||
onDelete: function({ row, col, cellValue, reload }) {
|
onDelete: function({ row, col, cellValue, reload }) {
|
||||||
|
|||||||
Reference in New Issue
Block a user