多维表格
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1166 lines
30 KiB

<template>
<div
@dragover.prevent="dragOver = true"
@dragenter.prevent="dragOver = true"
@dragexit="dragOver = false"
@dragleave="dragOver = false"
@dragend="dragOver = false"
@drop.prevent.stop="onFileDrop"
>
<table
v-if="data"
class="xc-row-table nc-grid backgroundColorDefault"
style=""
>
<thead>
<tr class="text-left nc-grid-header-row">
<th
class="grey-border caption"
:class="
$store.state.settings.darkTheme
? 'grey darken-3 grey--text text--lighten-1'
: 'grey lighten-4 grey--text text--darken-2'
"
style="width: 65px"
>
<div class="d-flex align-center">
<span v-if="!selectAll" class="row-no">#</span>
<template v-if="!isPublicView">
<v-checkbox
v-model="selectAll"
class="row-checkbox pt-0 align-self-center my-auto"
:class="{ active: selectAll }"
dense
/>
</template>
<div class="d-flex align-center" />
</div>
</th>
<th
v-for="col in availableColumns"
v-show="showFields[col.title]"
:key="col.title"
v-xc-ver-resize
class="grey-border caption font-wight-regular nc-grid-header-cell"
:class="
$store.state.settings.darkTheme
? 'grey darken-3 grey--text text--lighten-1'
: 'grey lighten-4 grey--text text--darken-2'
"
:data-col="col.title"
@xcresize="onresize(col.id, $event), log('xcresize')"
@xcresizing="onXcResizing(col.title, $event)"
@xcresized="resizingCol = null"
>
<!-- :style="columnsWidth[col.title] ? `min-width:${columnsWidth[col.title]}; max-width:${columnsWidth[col.title]}` : ''"
-->
<virtual-header-cell
v-if="isVirtualCol(col)"
:column="col"
:nodes="nodes"
:meta="meta"
:sql-ui="sqlUi"
:is-public-view="isPublicView"
:is-locked="isLocked"
:is-virtual="isVirtual"
@saved="onNewColCreation"
/>
<header-cell
v-else
:is-public-view="isPublicView"
:nodes="nodes"
:value="col.title"
:sql-ui="sqlUi"
:meta="meta"
:column-index="meta && meta.columns && meta.columns.indexOf(col)"
:column="col"
:is-virtual="isVirtual"
:is-locked="isLocked"
@onRelationDelete="$emit('onRelationDelete')"
@colDelete="$emit('colDelete')"
@saved="onNewColCreation"
/>
</th>
<th
v-if="
!isLocked &&
!isVirtual &&
!isPublicView &&
_isUIAllowed('add-column')
"
v-t="['c:column:add']"
:class="
$store.state.settings.darkTheme
? 'grey darken-3 grey--text text--lighten-1'
: 'grey lighten-4 grey--text text--darken-2'
"
class="grey-border new-column-header pointer nc-grid-header-cell"
@click="addNewColMenu = true"
>
<v-icon small @click="addNewColMenu = true">
mdi-plus
</v-icon>
<v-menu v-model="addNewColMenu" offset-y content-class="" left>
<template #activator="{ on }">
<span v-on="on" />
</template>
<edit-column
v-if="addNewColMenu"
:meta="meta"
:nodes="nodes"
:sql-ui="sqlUi"
@close="addNewColMenu = false"
@saved="onNewColCreation"
/>
</v-menu>
</th>
</tr>
</thead>
<tbody v-click-outside="onClickOutside">
<tr
v-for="({ row: rowObj, rowMeta, saving }, row) in data"
:key="row"
class="nc-grid-row"
:class="{
'nc-new-row': rowMeta.new,
'nc-saved-row': !rowMeta.new,
}"
>
<td
style="width: 65px"
class="caption nc-grid-cell"
@contextmenu="showRowContextMenu($event, rowObj, rowMeta, row)"
>
<div class="d-flex align-center">
<span
v-show="!rowMeta || !rowMeta.selected"
class="ml-2 grey--text"
:class="{ 'row-no': !isPublicView }"
>{{ row + 1 }}</span>
<template v-if="!isPublicView">
<v-checkbox
v-if="rowMeta"
v-model="rowMeta.selected"
class="row-checkbox pt-0 align-self-center my-auto"
:class="{ active: rowMeta.selected }"
dense
/>
<v-spacer />
<v-icon
v-if="!groupedAggCount[ids[row]] && !isLocked && !saving"
color="pink"
small
class="row-expand-icon nc-row-expand-icon mr-1 pointer"
@click="expandRow(row, rowMeta)"
>
mdi-arrow-expand
</v-icon>
</template>
<v-chip
v-if="groupedAggCount[ids[row]] && !saving"
x-small
:color="colors[groupedAggCount[ids[row]] % colors.length]"
@click="expandRow(row, rowMeta)"
>
{{ groupedAggCount[ids[row]] }}
</v-chip>
<template v-if="saving">
<v-spacer />
<v-icon small>
mdi-spin mdi-loading
</v-icon>
</template>
</div>
</td>
<td
v-for="(columnObj, col) in availableColumns"
v-show="showFields[columnObj.title]"
:key="row + columnObj.title"
class="cell pointer nc-grid-cell"
:class="{
active:
!isPublicView &&
selected.col === col &&
selected.row === row &&
isEditable,
'primary-column': primaryValueColumn === columnObj.title,
'text-center': isCentrallyAligned(columnObj),
required: isRequired(columnObj, rowObj),
}"
:data-col="columnObj.title"
@dblclick="makeEditable(col, row, columnObj.ai, rowMeta)"
@click="makeSelected(col, row)"
@contextmenu="
showRowContextMenu($event, rowObj, rowMeta, row, col, columnObj)
"
>
<virtual-cell
v-if="isVirtualCol(columnObj)"
:password="password"
:is-public="isPublicView"
:metas="metas"
:is-locked="isLocked"
:column="columnObj"
:row="rowObj"
:nodes="nodes"
:meta="meta"
:api="api"
:active="selected.col === col && selected.row === row"
:sql-ui="sqlUi"
:is-new="rowMeta.new"
v-on="$listeners"
@updateCol="
(...args) =>
updateCol(
...args,
columnObj.bt &&
meta.columns.find(
(c) => c.column_name === columnObj.bt.column_name
),
col,
row
)
"
@saveRow="onCellValueChange(col, row, columnObj, true)"
/>
<editable-cell
v-else-if="
((isPkAvail || rowMeta.new) &&
!isView &&
!isLocked &&
!isPublicView &&
editEnabled.col === col &&
editEnabled.row === row) ||
enableEditable(columnObj)
"
v-model="rowObj[columnObj.title]"
:column="columnObj"
:meta="meta"
:active="selected.col === col && selected.row === row"
:sql-ui="sqlUi"
:db-alias="nodes.dbAlias"
:is-locked="isLocked"
:is-public="isPublicView"
:view-id="viewId"
@save="editEnabled = {}; onCellValueChange(col, row, columnObj, true);"
@cancel="editEnabled = {}"
@update="onCellValueChange(col, row, columnObj, false)"
@blur="onCellValueChange(col, row, columnObj, true)"
@input="unsaved = true"
@navigateToNext="navigateToNext"
@navigateToPrev="navigateToPrev"
/>
<table-cell
v-else
:class="{
'primary--text': primaryValueColumn === columnObj.title,
}"
:selected="selected.col === col && selected.row === row"
:is-locked="isLocked"
:column="columnObj"
:meta="meta"
:db-alias="nodes.dbAlias"
:value="rowObj[columnObj.title]"
:sql-ui="sqlUi"
@enableedit="
makeSelected(col, row);
makeEditable(col, row, columnObj.ai, rowMeta);
"
/>
</td>
</tr>
<tr
v-if="
!isView &&
!isLocked &&
!isPublicView &&
isEditable &&
relationType !== 'bt'
"
>
<td
v-t="['c:row:add:grid-bottom']"
:colspan="visibleColLength + 1"
class="text-left pointer nc-grid-add-new-cell"
@click="insertNewRow(true)"
>
<v-tooltip top>
<template #activator="{ on }">
<v-icon small color="pink" v-on="on">
mdi-plus
</v-icon>
<span class="ml-1 caption grey--text">
{{ $t("activity.addRow") }}
</span>
</template>
<span class="caption"> Add new row</span>
</v-tooltip>
</td>
</tr>
</tbody>
</table>
<div is="style" v-html="style" />
<!-- <div is="style" v-html="resizeColStyle" />-->
<dynamic-style>
<template v-if="resizingCol">
[data-col="{{ resizingCol }}"]{min-width:{{
resizingColWidth
}};max-width:{{ resizingColWidth }};width:{{ resizingColWidth }};}
</template>
</dynamic-style>
</div>
</template>
<script>
import { isVirtualCol } from 'nocodb-sdk'
import HeaderCell from '../components/HeaderCell'
import EditableCell from '../components/EditableCell'
import EditColumn from '../components/EditColumn'
// import columnStyling from '../helpers/columnStyling'
import VirtualCell from '../components/VirtualCell'
import VirtualHeaderCell from '../components/VirtualHeaderCell'
import colors from '@/mixins/colors'
import TableCell from '~/components/project/spreadsheet/components/Cell'
import DynamicStyle from '~/components/DynamicStyle'
import { UITypes } from '~/components/project/spreadsheet/helpers/uiTypes'
import { copyTextToClipboard } from '~/helpers/xutils'
export default {
name: 'XcGridView',
components: {
DynamicStyle,
VirtualHeaderCell,
VirtualCell,
TableCell,
EditColumn,
EditableCell,
HeaderCell
},
mixins: [colors],
props: {
loading: Boolean,
droppable: Boolean,
isView: Boolean,
metas: Object,
relationType: String,
availableColumns: [Object, Array],
showFields: Object,
sqlUi: [Object, Function],
api: [Object, Function],
isEditable: Boolean,
nodes: Object,
primaryValueColumn: String,
// belongsTo: [Object, Array],
// hasMany: [Object, Array],
data: [Array, Object],
meta: Object,
visibleColLength: [Number, String],
isPublicView: Boolean,
table: String,
isVirtual: Boolean,
isLocked: Boolean,
// columnsWidth: { type: Object },
isPkAvail: Boolean,
password: String,
viewId: String
},
data: () => ({
resizingCol: null,
isVirtualCol,
resizingColWidth: null,
selectedExpandRowIndex: null,
selectedExpandRowMeta: null,
addNewColMenu: false,
selected: {
row: null,
col: null
},
editEnabled: {
row: null,
col: null
},
aggCount: [],
dragOver: false,
gridViewCols: {},
unsaved: false
}),
computed: {
selectAll: {
get() {
return !!(
this.data.length &&
this.data.every(d => d.rowMeta && d.rowMeta.selected)
)
},
set(v) {
for (const d of this.data) {
this.$set(d.rowMeta, 'selected', v)
}
}
},
ids() {
return (
(this.meta &&
this.meta.columns &&
this.data &&
this.data.map(({ oldRow }) =>
this.meta.columns
.filter(c => c.pk)
.map(c => oldRow[c.title])
.join('___')
)) ||
[]
)
},
haveHasManyrelation() {
return !!Object.keys(this.hasMany).length
},
colLength() {
return (this.availableColumns && this.availableColumns.length) || 0
},
rowLength() {
return (this.data && this.data.length) || 0
},
availColNames() {
return (
(this.availableColumns && this.availableColumns.map(c => c.title)) ||
[]
)
},
groupedAggCount() {
// eslint-disable-next-line camelcase
return this.aggCount
? this.aggCount.reduce(
(o, { row_id, count }) => ({
...o,
[row_id]: count
}),
{}
)
: {}
},
style() {
let style = ''
for (const c of this.availableColumns) {
const val =
(this.gridViewCols &&
this.gridViewCols[c.id] &&
this.gridViewCols[c.id].width) ||
'200px'
if (val && c.key !== this.resizingCol) {
style += `[data-col="${c.title}"]{min-width:${val};max-width:${val};width: ${val};}`
}
}
return style
}
// resizeColStyle() {
// return this.resizingCol ? ` [data-col="${this.resizingCol}"]{min-width:${this.resizingColWidth};max-width:${this.resizingColWidth};width:${this.resizingColWidth};}` : ''
// }
},
watch: {
data() {
this.xcAuditModelCommentsCount()
},
viewId(v, o) {
if (v !== o) {
this.loadGridViewCols()
}
}
},
mounted() {
// this.calculateColumnWidth()
},
created() {
document.addEventListener('keydown', this.onKeyDown)
this.loadGridViewCols()
this.xcAuditModelCommentsCount()
const self = this
window.addEventListener('beforeunload', function() {
if (self.unsaved) {
if (self.editEnabled.row != null && self.editEnabled.row != null) {
const columnObj = self.availableColumns[self.editEnabled.col]
self.onCellValueChange(
self.editEnabled.col,
self.editEnabled.row,
columnObj,
true
)
}
}
})
},
beforeDestroy() {
document.removeEventListener('keydown', this.onKeyDown)
},
methods: {
async loadGridViewCols() {
if (!this.viewId) {
return
}
const colsData = await this.$api.dbView.gridColumnsList(this.viewId)
this.gridViewCols = colsData.reduce(
(o, col) => ({
...o,
[col.fk_column_id]: col
}),
{}
)
},
onFileDrop(event) {
this.$emit('drop', event)
},
isRequired(_columnObj, rowObj, ignoreCurrentValue = false) {
if (this.isPublicView || this.loading) {
return false
}
let columnObj = _columnObj
if (columnObj.bt) {
columnObj = this.meta.columns.find(
c => c.column_name === columnObj.bt.column_name
)
}
return (
columnObj &&
columnObj.rqd &&
(ignoreCurrentValue ||
rowObj[columnObj.title] === undefined ||
rowObj[columnObj.title] === null) &&
!columnObj.default
)
},
updateCol(row, column, value, columnObj, colIndex, rowIndex) {
this.$set(row, column, value)
this.onCellValueChange(colIndex, rowIndex, columnObj, true)
},
calculateColumnWidth() {
// setTimeout(() => {
// const obj = {}
// this.meta && this.meta.columns && this.meta.columns.forEach((c) => {
// obj[c.title] = (columnStyling[c.uidt] && columnStyling[c.uidt].w) || undefined
// })
// this.meta && this.meta.v && this.meta.v.forEach((v) => {
// obj[v.title] = v.bt ? '100px' : '200px'
// })
// Array.from(this.$el.querySelectorAll('th')).forEach((el) => {
// const width = el.getBoundingClientRect().width
// obj[el.dataset.col] = obj[el.dataset.col] || ((width < 100 ? 100 : width) + 'px')
// })
// this.$emit('update:columnsWidth', { ...obj, ...(this.columnWidth || {}) })
// }, 2000)
},
isCentrallyAligned(col) {
return ![
'SingleLineText',
'LongText',
'Attachment',
'Date',
'Time',
'Email',
'URL',
'DateTime',
'CreateTime',
'LastModifiedTime'
].includes(col.uidt)
},
async xcAuditModelCommentsCount() {
if (this.isPublicView || !this.data || !this.data.length) {
return
}
// const aggCount = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
// dbAlias: this.nodes.dbAlias
// }, 'xcAuditModelCommentsCount', {
// model_name: this.meta.title,
// ids: this.data.map(({ row: r }) => {
// return this.meta.columns.filter(c => c.pk).map(c => r[c.title]).join('___')
// })
// }])
//
this.aggCount = await this.$api.utils.commentCount({
ids: this.data.map(({ row: r }) => {
return this.meta.columns
.filter(c => c.pk)
.map(c => r[c.title])
.join('___')
}),
fk_model_id: this.meta.id
})
},
async onKeyDown(e) {
if (
this.selected.col === null ||
this.selected.row === null ||
this.isLocked
) {
return
}
switch (e.keyCode) {
// tab
case 9:
e.preventDefault()
this.editEnabled = {
col: null,
row: null
}
if (e.shiftKey) {
if (this.selected.col > 0) {
this.selected.col--
} else if (this.selected.row > 0) {
this.selected.row--
this.selected.col = this.colLength - 1
}
} else if (this.selected.col < this.colLength - 1) {
this.selected.col++
} else if (this.selected.row < this.rowLength - 1) {
this.selected.row++
this.selected.col = 0
}
break
// delete
case 46:
{
if (this.editEnabled.col != null && this.editEnabled.row != null) {
return
}
const rowObj = this.data[this.selected.row].row
const columnObj = this.availableColumns[this.selected.col]
if (
// this.isRequired(columnObj, rowObj, true) ||
columnObj.virtual
) {
return
}
this.$set(rowObj, columnObj.title, null)
// update/save cell value
this.onCellValueChange(
this.selected.col,
this.selected.row,
columnObj,
true
)
}
break
// left
case 37:
if (this.selected.col > 0) {
this.selected.col--
}
break
// right
case 39:
if (this.selected.col < this.colLength - 1) {
this.selected.col++
}
break
// up
case 38:
if (this.selected.row > 0) {
this.selected.row--
}
break
// down
case 40:
if (this.selected.row < this.rowLength - 1) {
this.selected.row++
}
break
// enter
case 13:
this.makeEditable(this.selected.col, this.selected.row)
break
default: {
if (this.editEnabled.col != null && this.editEnabled.row != null) {
return
}
const rowObj = this.data[this.selected.row].row
const columnObj = this.availableColumns[this.selected.col]
if (e.metaKey || e.ctrlKey) {
switch (e.keyCode) {
// copy - ctrl/cmd +c
case 67:
copyTextToClipboard(rowObj[columnObj.title] || '')
break
// // paste ctrl/cmd + v
// case 86: {
// const text = await navigator.clipboard.readText()
// this.$set(rowObj, columnObj.title, text)
// }
// break
}
}
if (e.ctrlKey || e.altKey || e.metaKey) {
return
}
if (e.key && e.key.length === 1) {
if (!this.isPkAvail && !this.data[this.selected.row].rowMeta.new) {
return this.$toast
.info(
"Update not allowed for table which doesn't have primary Key"
)
.goAway(3000)
}
this.$set(
this.data[this.selected.row].row,
this.availableColumns[this.selected.col].title,
''
)
this.editEnabled = { ...this.selected }
}
}
}
},
onClickOutside() {
if (
(this.meta.columns &&
this.meta.columns[this.selected.col] &&
this.meta.columns[this.selected.col].virtual) ||
(this.availableColumns &&
this.availableColumns[this.editEnabled.col] &&
this.availableColumns[this.editEnabled.col].uidt === 'JSON')
) {
return
}
this.selected.col = null
this.selected.row = null
this.editEnabled.col = null
this.editEnabled.row = null
},
onNewColCreation(col, oldCol) {
this.addNewColMenu = false
this.addNewColModal = false
this.$emit('onNewColCreation', col, oldCol)
},
expandRow(...args) {
this.$emit('expandRow', ...args)
this.$e('c:row-expand')
},
showRowContextMenu($event, rowObj, rowMeta, row, ...rest) {
this.$emit('showRowContextMenu', $event, rowObj, rowMeta, row, ...rest)
},
onCellValueChange(col, row, column, saved) {
this.$emit('onCellValueChange', col, row, column, saved)
if (saved) {
this.unsaved = false
}
},
navigateToNext() {
if (this.selected.row < this.rowLength - 1) {
this.selected.row++
}
},
navigateToPrev() {
if (this.selected.row > 0) {
this.selected.row--
}
},
makeSelected(col, row) {
if (this.selected.col !== col || this.selected.row !== row) {
this.selected = {
col,
row
}
this.editEnabled = {}
}
},
makeEditable(col, row, _, rowMeta) {
if (this.isPublicView || !this.isEditable || this.isView) {
return
}
if (!this.isPkAvail && !rowMeta.new) {
return this.$toast
.info("Update not allowed for table which doesn't have primary Key")
.goAway(3000)
}
if (this.availableColumns[col].ai) {
return this.$toast
.info('Auto Increment field is not editable')
.goAway(3000)
}
if (this.availableColumns[col].pk && !this.data[row].rowMeta.new) {
return this.$toast
.info('Editing primary key not supported')
.goAway(3000)
}
if (this.editEnabled.col !== col || this.editEnabled.row !== row) {
this.editEnabled = {
col,
row
}
}
},
enableEditable(column) {
return (
(column && column.uidt === UITypes.Attachment) ||
(column && column.uidt === UITypes.SingleSelect) ||
(column && column.uidt === UITypes.MultiSelect) ||
(column && column.uidt === UITypes.DateTime) ||
(column && column.uidt === UITypes.Date) ||
(column && column.uidt === UITypes.Time) ||
(this.sqlUi &&
column.dt &&
this.sqlUi.getAbstractType(column) === 'boolean')
)
},
insertNewRow(atEnd = false, expand = false) {
this.$emit('insertNewRow', atEnd, expand)
},
async onresize(colId, size) {
const gridColId =
this.gridViewCols &&
this.gridViewCols[colId] &&
this.gridViewCols[colId].id
if (!gridColId) {
return
}
this.$set(this.gridViewCols[colId], 'width', size)
if (this._isUIAllowed('gridColUpdate')) {
await this.$api.dbView.gridColumnUpdate(gridColId, {
width: size
})
}
// this.$emit('update:columnsWidth', { ...this.columnsWidth, [col]: size })
},
onXcResizing(_cn, width) {
this.resizingCol = _cn
this.resizingColWidth = width
},
log(e, s) {
console.log(e.target, s)
}
}
}
</script>
<style scoped lang="scss">
::v-deep {
.resizer:hover,
.resizer:active,
.resizer:focus {
background: var(--v-primary-base);
cursor: col-resize;
}
.v-list-item--dense .v-list-item__icon,
.v-list--dense .v-list-item .v-list-item__icon {
margin-top: 4px;
margin-bottom: 4px;
}
.v-list-item--dense,
.v-list--dense .v-list-item {
min-height: 32px;
}
.v-input__control .v-input__slot .v-input--selection-controls__input {
transform: scale(0.85);
margin-right: 0;
}
.xc-toolbar .v-input__slot,
.navigation .v-input__slot {
box-shadow: none !important;
}
.navigation .v-input__slot input::placeholder {
font-size: 0.8rem;
}
.v-btn {
text-transform: capitalize;
}
.row-checkbox .v-input__control {
height: 24px !important;
}
tr:hover .xc-bt-chip {
margin-right: 0;
padding-right: 0 !important;
}
.xc-bt-chip {
margin-right: 24px;
transition: 0.4s margin-right, 0.4s padding-right;
}
.theme--light tbody tr:hover {
background: #eeeeee22;
}
.theme--dark tbody tr:hover {
background: #33333322;
}
.xc-border.search-box {
overflow: visible;
border-radius: 4px;
}
.xc-border.search-box .v-input {
transition: 0.4s border-color;
}
.xc-border.search-box .v-input--is-focused {
border: 1px solid var(--v-primary-base) !important;
margin: -1px;
}
.search-field.v-text-field.v-text-field--solo.v-input--dense
> .v-input__control {
min-height: auto;
}
.view .view-icon {
display: none;
transition: 0.3s display;
}
.view:hover .view-icon {
display: inline-block;
}
.view:hover .check-icon {
display: none;
}
.v-input__control label {
font-size: inherit;
}
}
table,
td,
th.grey-border,
th.grey.darken-3,
th.grey.lighten-4 {
border-right: 1px solid #7f828b33 !important;
border-left: 1px solid #7f828b33 !important;
border-bottom: 2px solid #7f828b33 !important;
border-top: 2px solid #7f828b33 !important;
border-collapse: collapse;
}
td,
th {
position: relative;
padding: 0 5px !important;
}
td.active::after,
td.active::before {
content: "";
position: absolute;
z-index: 3;
height: calc(100% + 2px);
width: calc(100% + 2px);
left: -1px;
top: -1px;
pointer-events: none;
}
td.active::after {
border: 2px solid var(--v-primary-lighten1);
}
td.active::before {
background: var(--v-primary-base);
opacity: 0.1;
}
.xc-row-table thead tr {
background: transparent;
}
.xc-row-table thead th {
/*background: ;*/
position: sticky;
top: 0;
//left: 0;
z-index: 6;
}
.row-expand-icon,
.row-checkbox {
opacity: 0;
}
tr:hover .row-expand-icon,
tr:hover .row-checkbox,
tr .row-checkbox.active {
opacity: 1;
}
tr:hover .row-no {
display: none;
}
td,
tr {
min-height: 31px !important;
/*height: 31px !important;*/
/*max-height: 31px !important;*/
}
.cell-height-medium td,
.cell-height-medium tr {
min-height: 35px !important;
/*height: 35px !important;*/
/*max-height: 35px !important;*/
}
.cell-height-large td,
.cell-height-large tr {
min-height: 40px !important;
/*height: 40px !important;*/
/*max-height: 40px !important;*/
}
.cell-height-xlarge td,
.cell-height-xlarge tr {
min-height: 50px !important;
/*height: 50px !important;*/
/*max-height: 50px !important;*/
}
.belongsto-col {
text-decoration: underline;
}
.belongsto-col:hover {
color: var(--v-primary-base);
}
.hasmany-col-menu-icon {
opacity: 0;
transition: 0.4s opacity, 0.4s max-width;
}
.hasmany-col-menu-icon.pv {
/*display: none ;*/
max-width: 0;
overflow: hidden;
}
tr:hover .hasmany-col-menu-icon {
opacity: 1;
/*display: inline-block;*/
max-width: 24px;
}
tbody tr:nth-of-type(odd) {
background-color: transparent;
}
tbody tr:hover {
background-color: #dddddd33 !important;
}
.views-navigation-drawer {
transition: 0.4s max-width, 0.4s min-width;
}
.cell {
font-size: 13px;
&.required {
box-shadow: inset 0 0 0 1px red;
}
}
th::before {
content: "";
position: absolute;
width: 100%;
background: inherit;
top: -2px;
height: 3px;
left: 0;
}
td.primary-column {
border-right-width: 2px !important;
}
.share-link-box {
position: relative;
z-index: 2;
}
.share-link-box::before {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: var(--v-primary-base);
opacity: 0.2;
content: "";
z-index: 1;
pointer-events: none;
}
.new-column-header:hover {
background: linear-gradient(#ffffff33, #ffffff33);
}
.new-column-header {
text-align: center;
min-width: 70px;
}
.advance-menu-divider {
width: calc(100% - 26px);
margin-left: 13px;
border-style: dashed;
margin-top: 5px;
margin-bottom: 5px;
}
.sort-grid {
display: grid;
grid-template-columns: 22px auto 100px;
column-gap: 6px;
row-gap: 6px;
}
.xc-row-table {
table-layout: fixed;
}
td {
overflow: hidden;
}
th:first-child,
td:first-child {
min-width: 100px;
}
.has-many-icon {
transform: rotate(90deg);
}
</style>