Browse Source

feat: Lookup - update meta data structure, Add icon

Signed-off-by: Pranav C <61551451+pranavxc@users.noreply.github.com>
pull/401/head
Pranav C 3 years ago
parent
commit
93da24c163
  1. 4
      packages/nc-gui/components/project/spreadsheet/components/editColumn.vue
  2. 75
      packages/nc-gui/components/project/spreadsheet/components/editColumn/lookupOptions.vue
  3. 6
      packages/nc-gui/components/project/spreadsheet/components/expandedForm.vue
  4. 2
      packages/nc-gui/components/project/spreadsheet/components/virtualCell.vue
  5. 44
      packages/nc-gui/components/project/spreadsheet/components/virtualCell/lookupCell.vue
  6. 22
      packages/nc-gui/components/project/spreadsheet/components/virtualHeaderCell.vue
  7. 2
      packages/nc-gui/components/project/spreadsheet/helpers/uiTypes.js
  8. 20
      packages/nc-gui/components/project/spreadsheet/mixins/spreadsheet.js
  9. 9
      packages/nc-gui/components/project/spreadsheet/rowsXcDataTable.vue
  10. 89
      packages/nc-gui/components/project/spreadsheet/views/xcGridView.vue
  11. 6
      packages/nc-gui/plugins/globalMixin.js
  12. 2
      packages/nc-gui/plugins/ncApis/index.js
  13. 8
      packages/nocodb/package-lock.json
  14. 2
      packages/nocodb/package.json
  15. 28
      packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts
  16. 10
      packages/nocodb/src/lib/noco/gql/GqlApiBuilder.ts
  17. 9
      packages/nocodb/src/lib/noco/rest/RestApiBuilder.ts

4
packages/nc-gui/components/project/spreadsheet/components/editColumn.vue

@ -20,6 +20,7 @@
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field <v-text-field
v-if="!isLookup"
ref="column" ref="column"
v-model="newColumn.cn" v-model="newColumn.cn"
hide-details="auto" hide-details="auto"
@ -32,7 +33,6 @@
label="Column name" label="Column name"
dense dense
outlined outlined
:disabled="isLookup"
@input="newColumn.altered = newColumn.altered || 8" @input="newColumn.altered = newColumn.altered || 8"
/> />
</v-col> </v-col>
@ -485,7 +485,7 @@ export default {
return this.$emit('saved') return this.$emit('saved')
} }
if (this.isLookup && this.$refs.lookup) { if (this.isLookup && this.$refs.lookup) {
await this.$refs.lookup.save() return await this.$refs.lookup.save()
} }
this.newColumn.tn = this.nodes.tn this.newColumn.tn = this.nodes.tn

75
packages/nc-gui/components/project/spreadsheet/components/editColumn/lookupOptions.vue

@ -12,14 +12,14 @@
label="Child Table" label="Child Table"
:full-width="false" :full-width="false"
:items="refTables" :items="refTables"
item-text="_tn" item-text="_ltn"
:item-value="v => v" :item-value="v => v"
:rules="[v => !!v || 'Required']" :rules="[v => !!v || 'Required']"
dense dense
> >
<template #item="{item}"> <template #item="{item}">
<span class="caption"><span class="font-weight-bold"> {{ <span class="caption"><span class="font-weight-bold"> {{
item._tn item._ltn
}}</span> <small>({{ relationNames[item.type] }}) }}</span> <small>({{ relationNames[item.type] }})
</small></span> </small></span>
</template> </template>
@ -35,7 +35,7 @@
label="Child column" label="Child column"
:full-width="false" :full-width="false"
:items="columnList" :items="columnList"
item-text="_cn" item-text="_lcn"
dense dense
:loading="loadingColumns" :loading="loadingColumns"
:item-value="v => v" :item-value="v => v"
@ -65,9 +65,46 @@ export default {
refTables() { refTables() {
return this.meta return this.meta
? [ ? [
...(this.meta.belongsTo || []).map(bt => ({ type: 'bt', relation: bt, tn: bt.rtn, _tn: bt._rtn })), ...(this.meta.belongsTo || []).map(({ rtn, _rtn, rcn, tn, cn }) => ({
...(this.meta.hasMany || []).map(hm => ({ type: 'hm', relation: hm, tn: hm.tn, _tn: hm._tn })), type: 'bt',
...(this.meta.manyToMany || []).map(mm => ({ type: 'mm', relation: mm, tn: mm.rtn, _tn: mm._rtn })) rtn,
_rtn,
rcn,
tn,
cn,
ltn: rtn,
_ltn: _rtn
})),
...(this.meta.hasMany || []).map(({
tn,
_tn,
cn,
rcn,
rtn
}) => ({
type: 'hm',
tn,
_tn,
cn,
rcn,
rtn,
ltn: tn,
_ltn: _tn
})),
...(this.meta.manyToMany || []).map(({ vtn, _vtn, vrcn, vcn, rtn, _rtn, rcn, tn, cn }) => ({
type: 'mm',
tn,
cn,
vtn,
_vtn,
vrcn,
rcn,
rtn,
vcn,
_rtn,
ltn: rtn,
_ltn: _rtn
}))
] ]
: [] : []
}, },
@ -76,18 +113,21 @@ export default {
this.lookup && this.lookup &&
this.lookup.table && this.lookup.table &&
this.$store.state.meta.metas && this.$store.state.meta.metas &&
this.$store.state.meta.metas[this.lookup.table.tn] && this.$store.state.meta.metas[this.lookup.table.ltn] &&
this.$store.state.meta.metas[this.lookup.table.tn].columns this.$store.state.meta.metas[this.lookup.table.ltn].columns
) || []).map(({ cn, _cn }) => ({ cn, _cn })) ) || []).map(({ cn, _cn }) => ({
lcn: cn,
_lcn: _cn
}))
} }
}, },
methods: { methods: {
checkLookupExist(v) { checkLookupExist(v) {
return (this.lookup.table && (this.meta.v || []).every(c => !( return (this.lookup.table && (this.meta.v || []).every(c => !(
c.lookup && c.lk &&
c.type === this.lookup.table.type && c.lk.type === this.lookup.table.type &&
c.tn === this.lookup.table.tn && c.lk.ltn === this.lookup.table.ltn &&
c.cn === v.cn c.lk.lcn === v.lcn
))) || 'Lookup already exist' ))) || 'Lookup already exist'
}, },
async onTableChange() { async onTableChange() {
@ -97,7 +137,7 @@ export default {
await this.$store.dispatch('meta/ActLoadMeta', { await this.$store.dispatch('meta/ActLoadMeta', {
dbAlias: this.nodes.dbAlias, dbAlias: this.nodes.dbAlias,
env: this.nodes.env, env: this.nodes.env,
tn: this.lookup.table.tn tn: this.lookup.table.ltn
}) })
} catch (e) { } catch (e) {
// ignore // ignore
@ -117,10 +157,11 @@ export default {
const meta = JSON.parse(JSON.stringify(this.$store.state.meta.metas[this.meta.tn])) const meta = JSON.parse(JSON.stringify(this.$store.state.meta.metas[this.meta.tn]))
meta.v.push({ meta.v.push({
// _cn: this.alias, _cn: this.alias,
lookup: true, lk: {
...this.lookup.table, ...this.lookup.table,
...this.lookup.column ...this.lookup.column
}
}) })
await this.$store.dispatch('sqlMgr/ActSqlOp', [{ await this.$store.dispatch('sqlMgr/ActSqlOp', [{
@ -131,7 +172,7 @@ export default {
meta meta
}]) }])
return this.$emit('saved', `${this.lookup.column._cn} (from ${this.lookup.table._tn})`) return this.$emit('saved', `${this.lookup.column._lcn} (from ${this.lookup.table._ltn})`)
} catch (e) { } catch (e) {
this.$toast.error(e.message).goAway(3000) this.$toast.error(e.message).goAway(3000)
} }

6
packages/nc-gui/components/project/spreadsheet/components/expandedForm.vue

@ -59,8 +59,11 @@
<v-container fluid style="height:70vh" class="py-0"> <v-container fluid style="height:70vh" class="py-0">
<v-row class="h-100"> <v-row class="h-100">
<v-col class="h-100 px-10" style="overflow-y: auto" cols="8" :offset="isNew || !toggleDrawer ? 2 : 0"> <v-col class="h-100 px-10" style="overflow-y: auto" cols="8" :offset="isNew || !toggleDrawer ? 2 : 0">
<div <template
v-for="(col,i) in fields" v-for="(col,i) in fields"
>
<div
v-if="!col.lk"
:key="i" :key="i"
:class="{ :class="{
'active-row' : active === col._cn, 'active-row' : active === col._cn,
@ -135,6 +138,7 @@
/> />
</div> </div>
</div> </div>
</template>
</v-col> </v-col>
<v-col <v-col
v-if="!isNew && toggleDrawer" v-if="!isNew && toggleDrawer"

2
packages/nc-gui/components/project/spreadsheet/components/virtualCell.vue

@ -118,7 +118,7 @@ export default {
return this.column && this.column.mm return this.column && this.column.mm
}, },
lookup() { lookup() {
return this.column && this.column.lookup return this.column && this.column.lk
} }
}, },
methods: { methods: {

44
packages/nc-gui/components/project/spreadsheet/components/virtualCell/lookupCell.vue

@ -63,42 +63,32 @@ export default {
return this.column && this.$ncApis.get({ return this.column && this.$ncApis.get({
env: this.nodes.env, env: this.nodes.env,
dbAlias: this.nodes.dbAlias, dbAlias: this.nodes.dbAlias,
table: this.column.tn table: this.column.lk.ltn
}) })
// return this.lookUpMeta && this.lookUpMeta._tn
// ? ApiFactory.create(
// this.$store.getters['project/GtrProjectType'],
// this.lookUpMeta._tn,
// this.lookUpMeta.columns,
// this,
// this.lookUpMeta
// )
// : null
}, },
lookUpMeta() { lookUpMeta() {
return this.$store.state.meta.metas[this.column.tn] return this.$store.state.meta.metas[this.column.lk.ltn]
}, },
assocMeta() { assocMeta() {
return this.column.type === 'mm' && this.$store.state.meta.metas[this.column.relation.vtn] return this.column.lk.type === 'mm' && this.$store.state.meta.metas[this.column.lk.vtn]
}, },
lookUpColumnAlias() { lookUpColumnAlias() {
if (!this.lookUpMeta || !this.column.cn) { if (!this.lookUpMeta || !this.column.lk.lcn) {
return return
} }
return (this.$store.state.meta.metas[this.column.tn].columns.find(cl => cl.cn === this.column.cn) || {})._cn return (this.$store.state.meta.metas[this.column.lk.ltn].columns.find(cl => cl.cn === this.column.lk.lcn) || {})._cn
}, },
localValueObj() { localValueObj() {
if (!this.column || !this.row) { if (!this.column || !this.row) {
return null return null
} }
switch (this.column.type) { switch (this.column.lk.type) {
case 'mm': case 'mm':
return this.row[`${this.column._tn}MMList`] return this.row[`${this.column.lk._ltn}MMList`]
case 'hm': case 'hm':
return this.row[`${this.column._tn}List`] return this.row[`${this.column.lk._ltn}List`]
case 'bt': case 'bt':
return this.row[`${this.column._tn}Read`] return this.row[`${this.column.lk._ltn}Read`]
default: default:
return null return null
} }
@ -113,19 +103,19 @@ export default {
return [this.localValueObj[this.lookUpColumnAlias]] return [this.localValueObj[this.lookUpColumnAlias]]
}, },
queryParams() { queryParams() {
switch (this.column.type) { switch (this.column.lk.type) {
case 'bt': case 'bt':
return { where: `(${this.lookUpMeta.columns.find(c => c.cn === this.column.relation.rcn)._cn},eq,${this.row[this.meta.columns.find(c => c.cn === this.column.relation.cn)._cn]})` } return { where: `(${this.lookUpMeta.columns.find(c => c.cn === this.column.lk.rcn)._cn},eq,${this.row[this.meta.columns.find(c => c.cn === this.column.lk.cn)._cn]})` }
case 'hm': case 'hm':
return { where: `(${this.lookUpMeta.columns.find(c => c.cn === this.column.relation.cn)._cn},eq,${this.row[this.meta.columns.find(c => c.cn === this.column.relation.rcn)._cn]})` } return { where: `(${this.lookUpMeta.columns.find(c => c.cn === this.column.lk.cn)._cn},eq,${this.row[this.meta.columns.find(c => c.cn === this.column.lk.rcn)._cn]})` }
case 'mm': case 'mm':
return this.assocMeta return this.assocMeta
? { ? {
conditionGraph: { conditionGraph: {
[this.assocMeta.tn]: { [this.assocMeta.tn]: {
relationType: 'hm', relationType: 'hm',
[this.assocMeta.columns.find(c => c.cn === this.column.relation.vcn).cn]: { [this.assocMeta.columns.find(c => c.cn === this.column.lk.vcn).cn]: {
eq: this.row[this.meta.columns.find(c => c.cn === this.column.relation.cn)._cn] eq: this.row[this.meta.columns.find(c => c.cn === this.column.lk.cn)._cn]
} }
} }
} }
@ -145,14 +135,14 @@ export default {
await this.$store.dispatch('meta/ActLoadMeta', { await this.$store.dispatch('meta/ActLoadMeta', {
env: this.nodes.env, env: this.nodes.env,
dbAlias: this.nodes.dbAlias, dbAlias: this.nodes.dbAlias,
tn: this.column.tn tn: this.column.lk.ltn
}) })
} }
if (this.column.type === 'mm' && !this.assocMeta) { if (this.column.lk.type === 'mm' && !this.assocMeta) {
await this.$store.dispatch('meta/ActLoadMeta', { await this.$store.dispatch('meta/ActLoadMeta', {
env: this.nodes.env, env: this.nodes.env,
dbAlias: this.nodes.dbAlias, dbAlias: this.nodes.dbAlias,
tn: this.column.relation.vtn tn: this.column.lk.vtn
}) })
} }
}, },

22
packages/nc-gui/components/project/spreadsheet/components/virtualHeaderCell.vue

@ -11,9 +11,17 @@
<v-icon v-else-if="column.mm" color="pink" x-small class="mr-1" v-on="on"> <v-icon v-else-if="column.mm" color="pink" x-small class="mr-1" v-on="on">
mdi-table-network mdi-table-network
</v-icon> </v-icon>
<v-icon v-else-if="column.lookup" color="pink" x-small class="mr-1" v-on="on"> <template v-else-if="column.lk">
mdi-table-network <v-icon v-if="column.lk.type === 'hm'" color="warning" x-small class="mr-1" v-on="on">
mdi-table-column-plus-before
</v-icon>
<v-icon v-else-if="column.lk.type === 'bt'" color="info" x-small class="mr-1" v-on="on">
mdi-table-column-plus-before
</v-icon> </v-icon>
<v-icon v-else-if="column.lk.type === 'mm'" color="pink" x-small class="mr-1" v-on="on">
mdi-table-column-plus-before
</v-icon>
</template>
<span class="name flex-grow-1" :title="column._cn" v-on="on" v-html="alias"> <span class="name flex-grow-1" :title="column._cn" v-on="on" v-html="alias">
@ -31,7 +39,7 @@
</v-icon> </v-icon>
</template> </template>
<v-list dense> <v-list dense>
<v-list-item v-if="!column.lookup" dense @click="editColumnMenu = true"> <v-list-item v-if="!column.lk" dense @click="editColumnMenu = true">
<x-icon small class="mr-1" color="primary"> <x-icon small class="mr-1" color="primary">
mdi-pencil mdi-pencil
</x-icon> </x-icon>
@ -112,7 +120,7 @@ export default {
}), }),
computed: { computed: {
alias() { alias() {
return this.column.lookup ? `${this.column._cn} <small class="grey--text text--darken-1">(from ${this.column._tn})</small>` : this.column._cn return this.column.lk ? `${this.column.lk._lcn} <small class="grey--text text--darken-1">(from ${this.column.lk._ltn})</small>` : this.column._cn
}, },
type() { type() {
if (this.column.bt) { if (this.column.bt) {
@ -184,8 +192,8 @@ export default {
return `'${this.column.mm._tn}' & '${this.column.mm._rtn}' have <br>many to many relation` return `'${this.column.mm._tn}' & '${this.column.mm._rtn}' have <br>many to many relation`
} else if (this.column.bt) { } else if (this.column.bt) {
return `'${this.column.bt._tn}' belongs to '${this.column.bt._rtn}'` return `'${this.column.bt._tn}' belongs to '${this.column.bt._rtn}'`
} else if (this.column.lookup) { } else if (this.column.lk) {
return `'${this.column._cn}' from '${this.column._tn}' (${this.column.type}))` return `'${this.column.lk._lcn}' from '${this.column.lk._ltn}' (${this.column.lk.type})`
} }
return '' return ''
} }
@ -240,7 +248,7 @@ export default {
} }
}, },
async deleteColumn() { async deleteColumn() {
if (this.column.lookup) { if (this.column.lk) {
await this.deleteLookupColumn() await this.deleteLookupColumn()
} else { } else {
await this.deleteRelation() await this.deleteRelation()

2
packages/nc-gui/components/project/spreadsheet/helpers/uiTypes.js

@ -14,7 +14,7 @@ const uiTypes = [
}, },
{ {
name: 'Lookup', name: 'Lookup',
icon: 'mdi-link-variant' icon: 'mdi-table-column-plus-before'
}, },
{ {
name: 'SingleLineText', name: 'SingleLineText',

20
packages/nc-gui/components/project/spreadsheet/mixins/spreadsheet.js

@ -98,8 +98,8 @@ export default {
{ {
const _ref = {} const _ref = {}
columns.forEach((c) => { columns.forEach((c) => {
if (c.virtual && c.lookup) { if (c.virtual && c.lk) {
c.alias = `${c._cn} (from ${c._tn})` c.alias = `${c.lk._lcn} (from ${c.lk._ltn})`
} else { } else {
c.alias = c._cn c.alias = c._cn
} }
@ -152,7 +152,7 @@ export default {
// todo: handle if virtual column missing // todo: handle if virtual column missing
// construct fields args based on lookup columns // construct fields args based on lookup columns
const fieldsObj = ((this.meta && this.meta.v && this.meta.v) || []).reduce((obj, vc) => { const fieldsObj = ((this.meta && this.meta.v && this.meta.v) || []).reduce((obj, vc) => {
if (!vc.lookup) { if (!vc.lk) {
return obj return obj
} }
@ -160,21 +160,21 @@ export default {
let index let index
let column let column
switch (vc.type) { switch (vc.lk.type) {
case 'mm': case 'mm':
index = nestedFields.mm.indexOf(vc.tn) + 1 index = nestedFields.mm.indexOf(vc.lk.ltn) + 1
key = `mfields${index}` key = `mfields${index}`
column = vc.cn column = vc.lk.lcn
break break
case 'hm': case 'hm':
index = nestedFields.hm.indexOf(vc.tn) + 1 index = nestedFields.hm.indexOf(vc.lk.ltn) + 1
key = `hfields${index}` key = `hfields${index}`
column = vc.cn column = vc.lk.lcn
break break
case 'bt': case 'bt':
index = nestedFields.bt.indexOf(vc.tn) + 1 index = nestedFields.bt.indexOf(vc.lk.ltn) + 1
key = `bfields${index}` key = `bfields${index}`
column = vc.cn column = vc.lk.lcn
break break
} }

9
packages/nc-gui/components/project/spreadsheet/rowsXcDataTable.vue

@ -184,7 +184,7 @@
> >
<div class="flex-grow-1 h-100" style="overflow-y: auto"> <div class="flex-grow-1 h-100" style="overflow-y: auto">
<div ref="table" style="height : calc(100% - 36px); overflow: auto;width:100%"> <div ref="table" style="height : calc(100% - 36px); overflow: auto;width:100%">
<v-skeleton-loader v-if="!dataLoaded && (loadingData || loadingMeta)" type="table" /> <v-skeleton-loader v-if="!dataLoaded && (loadingData || loadingData)" type="table" />
<template v-else-if="selectedView && (selectedView.type === 'table' || selectedView.show_as === 'grid' )"> <template v-else-if="selectedView && (selectedView.type === 'table' || selectedView.show_as === 'grid' )">
<xc-grid-view <xc-grid-view
:key="key" :key="key"
@ -601,7 +601,9 @@ export default {
async mounted() { async mounted() {
try { try {
await this.createTableIfNewTable() await this.createTableIfNewTable()
this.loadingMeta = true
await this.loadMeta() await this.loadMeta()
this.loadingMeta = false
if (this.relationType === 'hm') { if (this.relationType === 'hm') {
this.filters.push({ this.filters.push({
@ -935,10 +937,13 @@ export default {
if (updateShowFields) { if (updateShowFields) {
try { try {
const qp = JSON.parse(tableMeta.query_params) const qp = JSON.parse(tableMeta.query_params)
this.showFields = qp.showFields ? qp.showFields : this.showFields this.showFields = qp.showFields || this.showFields
if (col) { if (col) {
this.$set(this.showFields, col, true) this.$set(this.showFields, col, true)
} }
if (this.selectedViewId === tableMeta.id) {
this.columnsWidth = qp.columnsWidth || this.columnsWidth
}
} catch (e) { } catch (e) {
} }
} }

89
packages/nc-gui/components/project/spreadsheet/views/xcGridView.vue

@ -208,6 +208,7 @@
</table> </table>
<div is="style" v-html="style" /> <div is="style" v-html="style" />
<div is="style" v-html="resizeColStyle" />
</div> </div>
</template> </template>
@ -290,27 +291,17 @@ export default {
}, },
style() { style() {
let style = '' let style = ''
for (const [key, val] of Object.entries(this.columnsWidth || {})) { for (const c of this.availableColumns) {
if (val && key !== this.resizingCol) { const val = (this.columnsWidth && this.columnsWidth[c.alias]) || (c.virtual ? '200px' : (columnStyling[c.uidt] && columnStyling[c.uidt].w))
style += ` if (val && c.key !== this.resizingCol) {
[data-col="${key}"]{ style += `[data-col="${c.alias}"]{min-width:${val};max-width:${val};width: ${val};}`
min-width: ${val};
max-width: ${val};
width: ${val};
}
`
} else if (key === this.resizingCol) {
style += `
[data-col="${key}"]{
min-width: ${this.resizingColWidth};
max-width: ${this.resizingColWidth};
width: ${this.resizingColWidth};
}
`
} }
} }
return style return style
},
resizeColStyle() {
return this.resizingCol ? ` [data-col="${this.resizingCol}"]{min-width:${this.resizingColWidth};max-width:${this.resizingColWidth};width:${this.resizingColWidth};}` : ''
} }
}, },
watch: { watch: {
@ -344,20 +335,20 @@ export default {
this.onCellValueChange(colIndex, rowIndex, columnObj) this.onCellValueChange(colIndex, rowIndex, columnObj)
}, },
calculateColumnWidth() { calculateColumnWidth() {
setTimeout(() => { // setTimeout(() => {
const obj = {} // const obj = {}
this.meta && this.meta.columns && this.meta.columns.forEach((c) => { // this.meta && this.meta.columns && this.meta.columns.forEach((c) => {
obj[c._cn] = (columnStyling[c.uidt] && columnStyling[c.uidt].w) || undefined // obj[c._cn] = (columnStyling[c.uidt] && columnStyling[c.uidt].w) || undefined
}) // })
this.meta && this.meta.v && this.meta.v.forEach((v) => { // this.meta && this.meta.v && this.meta.v.forEach((v) => {
obj[v._cn] = v.bt ? '100px' : '200px' // obj[v._cn] = v.bt ? '100px' : '200px'
}) // })
Array.from(this.$el.querySelectorAll('th')).forEach((el) => { // Array.from(this.$el.querySelectorAll('th')).forEach((el) => {
const width = el.getBoundingClientRect().width // const width = el.getBoundingClientRect().width
obj[el.dataset.col] = obj[el.dataset.col] || ((width < 100 ? 100 : width) + 'px') // obj[el.dataset.col] = obj[el.dataset.col] || ((width < 100 ? 100 : width) + 'px')
}) // })
this.$emit('update:columnsWidth', { ...obj, ...(this.columnWidth || {}) }) // this.$emit('update:columnsWidth', { ...obj, ...(this.columnWidth || {}) })
}, 500) // }, 2000)
}, },
isCentrallyAligned(col) { isCentrallyAligned(col) {
return !['SingleLineText', return !['SingleLineText',
@ -372,7 +363,9 @@ export default {
'LastModifiedTime'].includes(col.uidt) 'LastModifiedTime'].includes(col.uidt)
}, },
async xcAuditModelCommentsCount() { async xcAuditModelCommentsCount() {
if (this.isPublicView || !this.data || !this.data.length) { return } if (this.isPublicView || !this.data || !this.data.length) {
return
}
const aggCount = await this.$store.dispatch('sqlMgr/ActSqlOp', [{ const aggCount = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
dbAlias: this.nodes.dbAlias dbAlias: this.nodes.dbAlias
}, 'xcAuditModelCommentsCount', { }, 'xcAuditModelCommentsCount', {
@ -386,23 +379,33 @@ export default {
}, },
onKeyDown(e) { onKeyDown(e) {
if (this.selected.col === null || this.selected.row === null) { return } if (this.selected.col === null || this.selected.row === null) {
return
}
switch (e.keyCode) { switch (e.keyCode) {
// left // left
case 37: case 37:
if (this.selected.col > 0) { this.selected.col-- } if (this.selected.col > 0) {
this.selected.col--
}
break break
// right // right
case 39: case 39:
if (this.selected.col < this.colLength - 1) { this.selected.col++ } if (this.selected.col < this.colLength - 1) {
this.selected.col++
}
break break
// up // up
case 38: case 38:
if (this.selected.row > 0) { this.selected.row-- } if (this.selected.row > 0) {
this.selected.row--
}
break break
// down // down
case 40: case 40:
if (this.selected.row < this.rowLength - 1) { this.selected.row++ } if (this.selected.row < this.rowLength - 1) {
this.selected.row++
}
break break
// enter // enter
case 13: case 13:
@ -424,7 +427,9 @@ export default {
this.meta.columns && this.meta.columns &&
this.meta.columns[this.selected.col] && this.meta.columns[this.selected.col] &&
this.meta.columns[this.selected.col].virtual this.meta.columns[this.selected.col].virtual
) { return } ) {
return
}
this.selected.col = null this.selected.col = null
this.selected.row = null this.selected.row = null
}, },
@ -452,7 +457,9 @@ export default {
} }
}, },
makeEditable(col, row) { makeEditable(col, row) {
if (this.isPublicView || !this.isEditable) { return } if (this.isPublicView || !this.isEditable) {
return
}
if (this.availableColumns[col].ai) { if (this.availableColumns[col].ai) {
return this.$toast.info('Auto Increment field is not editable').goAway(3000) return this.$toast.info('Auto Increment field is not editable').goAway(3000)
} }
@ -777,8 +784,4 @@ th:first-child, td:first-child {
transform: rotate(90deg); transform: rotate(90deg);
} }
th {
min-width: 100px;
}
</style> </style>

6
packages/nc-gui/plugins/globalMixin.js

@ -48,8 +48,6 @@ export default async({ store }) => {
el.appendChild(resizer) el.appendChild(resizer)
resizer.addEventListener('mousedown', initDrag, false) resizer.addEventListener('mousedown', initDrag, false)
el.style.transition = '20ms width0'
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
let startX, startY, startWidth let startX, startY, startWidth
@ -76,10 +74,8 @@ export default async({ store }) => {
function doDrag(e) { function doDrag(e) {
width = (startWidth + e.clientX - startX) + 'px' width = (startWidth + e.clientX - startX) + 'px'
el.style.maxWidth = el.style.minWidth = el.style.width = width el.style.width = width
emit(vnode, 'xcresizing', width) emit(vnode, 'xcresizing', width)
//
// p.style.height = (startHeight + e.clientY - startY) + 'px';
} }
function stopDrag(e) { function stopDrag(e) {

2
packages/nc-gui/plugins/ncApis/index.js

@ -5,7 +5,7 @@ export default function({ store: $store, $axios, ...rest }, inject) {
let projectId = null let projectId = null
inject('ncApis', { inject('ncApis', {
get: ({ table, dbAlias, env }) => { get: ({ table, dbAlias = 'db', env = 'dev' }) => {
if (!$store.state.meta.metas[table]) { if (!$store.state.meta.metas[table]) {
return return
} }

8
packages/nocodb/package-lock.json generated

@ -1,6 +1,6 @@
{ {
"name": "nocodb", "name": "nocodb",
"version": "0.11.1", "version": "0.11.2",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -11800,9 +11800,9 @@
"integrity": "sha512-3AryS9uwa5NfISLxMciUonrH7YfXp+nlahB9T7girXIsLQrmwX4MdnuKs32akduCOGpKmjTJSWmATULbuMkbfw==" "integrity": "sha512-3AryS9uwa5NfISLxMciUonrH7YfXp+nlahB9T7girXIsLQrmwX4MdnuKs32akduCOGpKmjTJSWmATULbuMkbfw=="
}, },
"nc-help": { "nc-help": {
"version": "0.2.7", "version": "0.2.8",
"resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.7.tgz", "resolved": "https://registry.npmjs.org/nc-help/-/nc-help-0.2.8.tgz",
"integrity": "sha512-31wxoJmfZHJ4aP/YiI+GgZRqwulyB6Z5BamcCUw/NDdNVoze+zHX0CtmoxfSlyi/U4zUOG9rhennKPv6QmmsMQ==", "integrity": "sha512-h6HUWb2trYEVm7x2/hWxifeq+ZALCIFxZFISgpI/IQPhe/BSoGUNpcRIhWg8wt1y87kxZ7/VCkvTQUhW9OTOGg==",
"requires": { "requires": {
"axios": "^0.21.1", "axios": "^0.21.1",
"boxen": "^4.2.0", "boxen": "^4.2.0",

2
packages/nocodb/package.json

@ -144,7 +144,7 @@
"mysql2": "^2.2.5", "mysql2": "^2.2.5",
"nanoid": "^3.1.20", "nanoid": "^3.1.20",
"nc-common": "0.0.6", "nc-common": "0.0.6",
"nc-help": "^0.2.7", "nc-help": "^0.2.8",
"nc-lib-gui": "^0.2.9", "nc-lib-gui": "^0.2.9",
"nc-plugin": "^0.1.1", "nc-plugin": "^0.1.1",
"nodemailer": "^6.4.10", "nodemailer": "^6.4.10",

28
packages/nocodb/src/lib/noco/common/BaseApiBuilder.ts

@ -474,10 +474,10 @@ export default abstract class BaseApiBuilder<T extends Noco> implements XcDynami
// update lookup columns // update lookup columns
this.metas[bt.rtn].v?.forEach(v => { this.metas[bt.rtn].v?.forEach(v => {
if (v.tn === tn && v.cn === column.cno) { if (v.lk && v.lk.ltn === tn && v.lk.lcn === column.cno) {
relationTableMetas.add(this.metas[bt.rtn]) relationTableMetas.add(this.metas[bt.rtn])
v.cn = column.cn; v.lk.lcn = column.cn;
v._cn = column._cn; v.lk._lcn = column._cn;
} }
}) })
} }
@ -503,10 +503,10 @@ export default abstract class BaseApiBuilder<T extends Noco> implements XcDynami
// update lookup columns // update lookup columns
this.metas[hm.tn].v?.forEach(v => { this.metas[hm.tn].v?.forEach(v => {
if (v.tn === tn && v.cn === column.cno) { if (v.lk && v.lk.ltn === tn && v.lk.lcn === column.cno) {
relationTableMetas.add(this.metas[hm.tn]) relationTableMetas.add(this.metas[hm.tn])
v.cn = column.cn; v.lk.lcn = column.cn;
v._cn = column._cn; v.lk._lcn = column._cn;
} }
}) })
@ -533,10 +533,10 @@ export default abstract class BaseApiBuilder<T extends Noco> implements XcDynami
// update lookup columns // update lookup columns
this.metas[mm.rtn].v?.forEach(v => { this.metas[mm.rtn].v?.forEach(v => {
if (v.tn === tn && v.cn === column.cno) { if (v.lk &&v.lk.ltn === tn && v.lk.lcn === column.cno) {
relationTableMetas.add(this.metas[mm.tn]) relationTableMetas.add(this.metas[mm.tn])
v.cn = column.cn; v.lk.lcn = column.cn;
v._cn = column._cn; v.lk._lcn = column._cn;
} }
}) })
@ -598,7 +598,7 @@ export default abstract class BaseApiBuilder<T extends Noco> implements XcDynami
for (const bt of newMeta.belongsTo) { for (const bt of newMeta.belongsTo) {
// filter out lookup columns which maps to current col // filter out lookup columns which maps to current col
this.metas[bt.rtn].v = this.metas[bt.rtn].v?.filter(v => { this.metas[bt.rtn].v = this.metas[bt.rtn].v?.filter(v => {
if (v.lookup && v.tn === tn && v.cn === column.cn) { if (v.lk && v.lk.ltn === tn && v.lk.lcn === column.cn) {
relationTableMetas.add(this.metas[bt.rtn]) relationTableMetas.add(this.metas[bt.rtn])
return false; return false;
} }
@ -613,7 +613,7 @@ export default abstract class BaseApiBuilder<T extends Noco> implements XcDynami
for (const hm of newMeta.hasMany) { for (const hm of newMeta.hasMany) {
// filter out lookup columns which maps to current col // filter out lookup columns which maps to current col
this.metas[hm.tn].v = this.metas[hm.tn].v?.filter(v => { this.metas[hm.tn].v = this.metas[hm.tn].v?.filter(v => {
if (v.lookup && v.tn === tn && v.cn === column.cn) { if (v.lk && v.lk.ltn === tn && v.lk.lcn === column.cn) {
relationTableMetas.add(this.metas[hm.tn]) relationTableMetas.add(this.metas[hm.tn])
return false; return false;
} }
@ -627,7 +627,7 @@ export default abstract class BaseApiBuilder<T extends Noco> implements XcDynami
for (const mm of newMeta.manyToMany) { for (const mm of newMeta.manyToMany) {
// filter out lookup columns which maps to current col // filter out lookup columns which maps to current col
this.metas[mm.rtn].v=this.metas[mm.rtn].v?.filter(v => { this.metas[mm.rtn].v=this.metas[mm.rtn].v?.filter(v => {
if (v.tn === tn && v.rcn === column.cn) { if (v.lk && v.lk.ltn === tn && v.lk.lcn === column.cn) {
relationTableMetas.add(this.metas[mm.tn]) relationTableMetas.add(this.metas[mm.tn])
return false; return false;
} }
@ -904,11 +904,11 @@ export default abstract class BaseApiBuilder<T extends Noco> implements XcDynami
// filter lookup and relation virtual columns // filter lookup and relation virtual columns
parentMeta.v = parentMeta.v.filter(({mm, ...rest}) => (!mm || !(mm.tn === parent && mm.rtn === child || mm.tn === child && mm.rtn === parent)) parentMeta.v = parentMeta.v.filter(({mm, ...rest}) => (!mm || !(mm.tn === parent && mm.rtn === child || mm.tn === child && mm.rtn === parent))
// check for lookup // check for lookup
&& !(rest.type === 'mm' && (rest.relation.tn === parent && rest.relation.rtn === child || rest.relation.tn === child && rest.relation.rtn === parent)) && !(rest.lk && rest.lk.type === 'mm' && (rest.lk.tn === parent && rest.lk.rtn === child || rest.lk.tn === child && rest.lk.rtn === parent))
) )
childMeta.v = childMeta.v.filter(({mm, ...rest}) => (!mm || !(mm.tn === parent && mm.rtn === child || mm.tn === child && mm.rtn === parent)) childMeta.v = childMeta.v.filter(({mm, ...rest}) => (!mm || !(mm.tn === parent && mm.rtn === child || mm.tn === child && mm.rtn === parent))
// check for lookup // check for lookup
&& !(rest.type === 'mm' && (rest.relation.tn === parent && rest.relation.rtn === child || rest.relation.tn === child && rest.relation.rtn === parent)) && !(rest.lk && rest.lk.type === 'mm' && (rest.lk.tn === parent && rest.lk.rtn === child || rest.lk.tn === child && rest.lk.rtn === parent))
) )
for (const meta of [parentMeta, childMeta]) { for (const meta of [parentMeta, childMeta]) {

10
packages/nocodb/src/lib/noco/gql/GqlApiBuilder.ts

@ -1380,8 +1380,8 @@ export class GqlApiBuilder extends BaseApiBuilder<Noco> implements XcMetaMgr {
const oldMeta = JSON.parse(existingModel.meta); const oldMeta = JSON.parse(existingModel.meta);
Object.assign(oldMeta, { Object.assign(oldMeta, {
hasMany: meta.hasMany, hasMany: meta.hasMany,
v: oldMeta.v.filter(({hm, lookup, relation, type}) => (!hm || hm.rtn !== tnp || hm.tn !== tnc) && v: oldMeta.v.filter(({hm, lk}) => (!hm || hm.rtn !== tnp || hm.tn !== tnc) &&
!(lookup && relation && type === 'hm' && relation.rtn === tnp && relation.tn === tnc)) !(lk && lk.type === 'hm' && lk.rtn === tnp && lk.tn === tnc))
}); });
// todo: backup schema // todo: backup schema
await this.xcMeta.metaUpdate(this.projectId, this.dbAlias, 'nc_models', { await this.xcMeta.metaUpdate(this.projectId, this.dbAlias, 'nc_models', {
@ -1430,8 +1430,8 @@ export class GqlApiBuilder extends BaseApiBuilder<Noco> implements XcMetaMgr {
const oldMeta = JSON.parse(existingModel.meta); const oldMeta = JSON.parse(existingModel.meta);
Object.assign(oldMeta, { Object.assign(oldMeta, {
belongsTo: meta.belongsTo, belongsTo: meta.belongsTo,
v: oldMeta.v.filter(({bt, lookup, relation, type}) => (!bt || bt.rtn !== tnp || bt.tn !== tnc) && v: oldMeta.v.filter(({bt, lk}) => (!bt || bt.rtn !== tnp || bt.tn !== tnc) &&
!(lookup && relation && type === 'bt' && relation.rtn === tnp && relation.tn === tnc)) !(lk && lk.type === 'bt' && lk.rtn === tnp && lk.tn === tnc))
}); });
await this.xcMeta.metaUpdate(this.projectId, this.dbAlias, 'nc_models', { await this.xcMeta.metaUpdate(this.projectId, this.dbAlias, 'nc_models', {
title: tnc, title: tnc,
@ -1963,3 +1963,5 @@ export class GqlApiBuilder extends BaseApiBuilder<Noco> implements XcMetaMgr {
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */

9
packages/nocodb/src/lib/noco/rest/RestApiBuilder.ts

@ -1,4 +1,3 @@
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
@ -1215,8 +1214,8 @@ export class RestApiBuilder extends BaseApiBuilder<Noco> {
const oldMeta = JSON.parse(existingModel.meta); const oldMeta = JSON.parse(existingModel.meta);
Object.assign(oldMeta, { Object.assign(oldMeta, {
hasMany: meta.hasMany, hasMany: meta.hasMany,
v: oldMeta.v.filter(({hm, lookup, relation, type}) => (!hm || hm.rtn !== tnp || hm.tn !== tnc) && v: oldMeta.v.filter(({hm, lk}) => (!hm || hm.rtn !== tnp || hm.tn !== tnc) &&
!(lookup && relation && type==='hm'&&relation.rtn === tnp && relation.tn === tnc )) !(lk && lk.type === 'hm' && lk.rtn === tnp && lk.tn === tnc))
}); });
// todo: delete from query_params // todo: delete from query_params
@ -1252,8 +1251,8 @@ export class RestApiBuilder extends BaseApiBuilder<Noco> {
Object.assign(oldMeta, { Object.assign(oldMeta, {
belongsTo: meta.belongsTo, belongsTo: meta.belongsTo,
v: oldMeta.v.filter(({bt, relation, lookup,type}) => (!bt || bt.rtn !== tnp || bt.tn !== tnc) && v: oldMeta.v.filter(({bt, lk}) => (!bt || bt.rtn !== tnp || bt.tn !== tnc) &&
!(lookup && relation && type==='bt'&&relation.rtn === tnp && relation.tn === tnc )) !(lk && lk.type === 'bt' && lk.rtn === tnp && lk.tn === tnc))
}); });
// todo: delete from query_params // todo: delete from query_params
await this.xcMeta.metaUpdate(this.projectId, await this.xcMeta.metaUpdate(this.projectId,

Loading…
Cancel
Save