Browse Source

refactor(gui-v2): code cleanup

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2716/head
Pranav C 2 years ago
parent
commit
628f1a5d00
  1. 19
      packages/nc-gui-v2/components/smartsheet-header/Cell.vue
  2. 29
      packages/nc-gui-v2/components/smartsheet-header/VirtualCellIcon.vue
  3. 456
      packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilter.vue
  4. 75
      packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilterMenu.vue
  5. 160
      packages/nc-gui-v2/components/smartsheet-toolbar/SortListMenu.vue
  6. 2
      packages/nc-gui-v2/utils/filterUtils.ts

19
packages/nc-gui-v2/components/smartsheet-header/Cell.vue

@ -71,25 +71,6 @@ export default {
<template>
<div class="d-flex align-center d-100">
<!--
<v-icon v-if="column.pk" color="warning" x-small class="mr-1"> mdi-key-variant</v-icon>
<v-icon v-else-if="uiDatatypeIcon" small class="mr-1">
{{ uiDatatypeIcon }}
</v-icon>
<v-icon v-else-if="isForeignKey" color="purple" small class="mr-1"> mdi-link-variant</v-icon>
<v-icon v-else-if="isJSON" color="purple" small class="mr-1"> mdi-code-json</v-icon>
<span v-else-if="isInt" class="font-weight-bold mr-1" style="font-size: 15px">#</span>
<v-icon v-else-if="isFloat" color="grey" class="mr-1 mt-n1"> mdi-decimal</v-icon>
<v-icon v-else-if="isDate" color="grey" small class="mr-1"> mdi-calendar</v-icon>
<v-icon v-else-if="isDateTime" color="grey" small class="mr-1"> mdi-calendar-clock</v-icon>
<v-icon v-else-if="isSet" color="grey" small class="mr-1"> mdi-checkbox-multiple-marked</v-icon>
<v-icon v-else-if="isEnum" color="grey" small class="mr-1"> mdi-radiobox-marked</v-icon>
<v-icon v-else-if="isBoolean" color="grey" small class="mr-1"> mdi-check-box-outline</v-icon>
<v-icon v-else-if="isString" color="grey" class=""> mdi-alpha-a</v-icon>
<v-icon v-else-if="isTextArea" color="grey" small class="mr-1"> mdi-card-text-outline</v-icon>
-->
<SmartsheetHeaderCellIcon v-if="column" />
<span v-if="column" class="name" style="white-space: nowrap" :title="column.title">{{ column.title }}</span>

29
packages/nc-gui-v2/components/smartsheet-header/VirtualCellIcon.vue

@ -31,35 +31,6 @@ const icon = computed(() => {
}
return GenericIcon
})
/*
*
<v-icon v-else-if="type === 'formula'" x-small class="mr-1" v-on="on">
mdi-math-integral
</v-icon>
<template v-else-if="type === 'lk'">
<v-icon v-if="relationType === 'hm'" color="warning" x-small class="mr-1" v-on="on">
mdi-table-column-plus-before
</v-icon>
<v-icon v-else-if="relationType === 'bt'" color="info" x-small class="mr-1" v-on="on">
mdi-table-column-plus-before
</v-icon>
<v-icon v-else-if="relationType === 'mm'" color="pink" x-small class="mr-1" v-on="on">
mdi-table-column-plus-before
</v-icon>
</template>
<template v-else-if="type === 'rl'">
<v-icon v-if="relationType === 'hm'" color="warning" x-small class="mr-1" v-on="on">
{{ rollupIcon }}
</v-icon>
<v-icon v-else-if="relationType === 'bt'" color="info" x-small class="mr-1" v-on="on">
{{ rollupIcon }}
</v-icon>
<v-icon v-else-if="relationType === 'mm'" color="pink" x-small class="mr-1" v-on="on">
{{ rollupIcon }}
</v-icon>
</template>
* */
</script>
<template>

456
packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilter.vue

@ -3,7 +3,7 @@ import { UITypes } from 'nocodb-sdk'
import FieldListAutoCompleteDropdown from './FieldListAutoCompleteDropdown.vue'
import { useNuxtApp } from '#app'
import { inject } from '#imports'
import { comparisonOp } from '~/utils/filterUtils'
import { comparisonOpList } from '~/utils/filterUtils'
import { ActiveViewInj, MetaInj, ReloadViewDataHookInj } from '~/components'
import useViewFilters from '~/composables/useViewFilters'
import MdiDeleteIcon from '~icons/mdi/close-box'
@ -28,7 +28,7 @@ const filterUpdateCondition = (filter, i) => {
})
}
// todo
// todo : filter based on type
// const filterComparisonOp = (f) =>
// comparisonOp.filter((op) => {
// // if (
@ -69,311 +69,6 @@ watch(
},
{ immediate: true },
)
/* import { UITypes, getUIDTIcon } from '~/components/project/spreadsheet/helpers/uiTypes'
import FieldListAutoCompleteDropdown from '~/components/project/spreadsheet/components/FieldListAutoCompleteDropdown'
export default {
name: 'ColumnFilter',
components: {
FieldListAutoCompleteDropdown,
},
props: {
fieldList: [Array],
meta: Object,
nested: Boolean,
parentId: String,
viewId: String,
shared: Boolean,
webHook: Boolean,
hookId: String,
},
data: () => ({
filters: [],
opList: [
'is equal',
'is not equal',
'is like',
'is not like',
// 'is empty', 'is not empty',
'is null',
'is not null',
'>',
'<',
'>=',
'<=',
],
comparisonOp: [
{
text: 'is equal',
value: 'eq',
},
{
text: 'is not equal',
value: 'neq',
},
{
text: 'is like',
value: 'like',
},
{
text: 'is not like',
value: 'nlike',
},
{
text: 'is empty',
value: 'empty',
ignoreVal: true,
},
{
text: 'is not empty',
value: 'notempty',
ignoreVal: true,
},
{
text: 'is null',
value: 'null',
ignoreVal: true,
},
{
text: 'is not null',
value: 'notnull',
ignoreVal: true,
},
{
text: '>',
value: 'gt',
},
{
text: '<',
value: 'lt',
},
{
text: '>=',
value: 'gte',
},
{
text: '<=',
value: 'lte',
},
],
}),
computed: {
columnIcon() {
return this.meta.columns.reduce((iconsObj, c) => {
return { ...iconsObj, [c.title]: getUIDTIcon(c.uidt) }
}, {})
},
columnsById() {
return (this.columns || []).reduce((o, c) => ({ ...o, [c.id]: c }), {})
},
autoApply() {
return this.$store.state.settings.autoApplyFilter && !this.webHook
},
columns() {
return (
this.meta &&
this.meta.columns
.filter((c) => c && (!c.colOptions || !c.system))
.map((c) => ({
...c,
icon: getUIDTIcon(c.uidt),
}))
)
},
types() {
if (!this.meta || !this.meta.columns || !this.meta.columns.length) {
return {}
}
return this.meta.columns.reduce((obj, col) => {
switch (col.uidt) {
case UITypes.Number:
case UITypes.Decimal:
obj[col.title] = obj[col.column_name] = 'number'
break
case UITypes.Checkbox:
obj[col.title] = obj[col.column_name] = 'boolean'
break
default:
break
}
return obj
}, {})
},
},
watch: {
async viewId(v) {
if (v) {
await this.loadFilter()
}
},
filters: {
handler(v) {
this.$emit('input', v && v.filter((f) => (f.fk_column_id && f.comparison_op) || f.is_group))
},
deep: true,
},
},
created() {
this.loadFilter()
},
methods: {
filterComparisonOp(f) {
return this.comparisonOp.filter((op) => {
if (
f &&
f.fk_column_id &&
this.columnsById[f.fk_column_id] &&
this.columnsById[f.fk_column_id].uidt === UITypes.LinkToAnotherRecord &&
this.columnsById[f.fk_column_id].uidt === UITypes.Lookup
) {
return !['notempty', 'empty', 'notnull', 'null'].includes(op.value)
}
return true
})
},
async applyChanges(nested = false, { hookId } = {}) {
for (const [i, filter] of Object.entries(this.filters)) {
if (filter.status === 'delete') {
if (this.hookId || hookId) {
await this.$api.dbTableFilter.delete(filter.id)
} else {
await this.$api.dbTableFilter.delete(filter.id)
}
} else if (filter.status === 'update') {
if (filter.id) {
if (this.hookId || hookId) {
await this.$api.dbTableFilter.update(filter.id, {
...filter,
fk_parent_id: this.parentId,
})
} else {
await this.$api.dbTableFilter.update(filter.id, {
...filter,
fk_parent_id: this.parentId,
})
}
} else if (this.hookId || hookId) {
this.$set(
this.filters,
i,
await this.$api.dbTableWebhookFilter.create(this.hookId || hookId, {
...filter,
fk_parent_id: this.parentId,
}),
)
} else {
this.$set(
this.filters,
i,
await this.$api.dbTableFilter.create(this.viewId, {
...filter,
fk_parent_id: this.parentId,
}),
)
}
}
}
if (this.$refs.nestedFilter) {
for (const nestedFilter of this.$refs.nestedFilter) {
await nestedFilter.applyChanges(true)
}
}
this.loadFilter()
if (!nested) {
this.$emit('updated')
}
},
async loadFilter() {
let filters = []
if (this.viewId && this._isUIAllowed('filterSync')) {
filters = this.parentId
? await this.$api.dbTableFilter.childrenRead(this.parentId)
: await this.$api.dbTableFilter.read(this.viewId)
}
if (this.hookId && this._isUIAllowed('filterSync')) {
filters = this.parentId
? await this.$api.dbTableFilter.childrenRead(this.parentId)
: await this.$api.dbTableWebhookFilter.read(this.hookId)
}
this.filters = filters
},
addFilter() {
this.filters.push({
fk_column_id: null,
comparison_op: 'eq',
value: '',
status: 'update',
logical_op: 'and',
})
this.filters = this.filters.slice()
this.$e('a:filter:add', { length: this.filters.length })
},
addFilterGroup() {
this.filters.push({
parentId: this.parentId,
is_group: true,
status: 'update',
})
this.filters = this.filters.slice()
const index = this.filters.length - 1
this.saveOrUpdate(this.filters[index], index)
},
filterUpdateCondition(filter, i) {
this.saveOrUpdate(filter, i)
this.$e('a:filter:update', {
logical: filter.logical_op,
comparison: filter.comparison_op,
})
},
async saveOrUpdate(filter, i) {
if (this.shared || !this._isUIAllowed('filterSync')) {
// this.$emit('input', this.filters.filter(f => f.fk_column_id && f.comparison_op))
this.$emit('updated')
} else if (!this.autoApply) {
filter.status = 'update'
} else if (filter.id) {
await this.$api.dbTableFilter.update(filter.id, {
...filter,
fk_parent_id: this.parentId,
})
this.$emit('updated')
} else {
this.$set(
this.filters,
i,
await this.$api.dbTableFilter.create(this.viewId, {
...filter,
fk_parent_id: this.parentId,
}),
)
this.$emit('updated')
}
},
async deleteFilter(filter, i) {
if (this.shared || !this._isUIAllowed('filterSync')) {
this.filters.splice(i, 1)
this.$emit('updated')
} else if (filter.id) {
if (!this.autoApply) {
this.$set(filter, 'status', 'delete')
} else {
await this.$api.dbTableFilter.delete(filter.id)
await this.loadFilter()
this.$emit('updated')
}
} else {
this.filters.splice(i, 1)
this.$emit('updated')
}
this.$e('a:filter:delete')
},
},
} */
</script>
<template>
@ -475,7 +170,7 @@ export default {
<v-select
v-model="filter.comparison_op"
class="caption nc-filter-operation-select text-sm"
:items="comparisonOp.map((it) => it.value)"
:items="comparisonOpList.map((it) => it.value)"
:placeholder="$t('labels.operation')"
density="compact"
variant="solo"
@ -526,151 +221,6 @@ export default {
</v-btn>
<slot />
</div>
<!-- <div class="backgroundColor pa-2 menu-filter-dropdown" :style="{ width: nested ? '100%' : '530px' }">
<div class="grid" @click.stop>
<template v-for="(filter, i) in filters" dense>
<template v-if="filter.status !== 'delete'">
<div v-if="filter.is_group" :key="i" style="grid-column: span 4; padding: 6px" class="elevation-4">
<div class="d-flex" style="gap: 6px; padding: 0 6px">
<v-icon
v-if="!filter.readOnly"
:key="`${i}_3`"
small
class="nc-filter-item-remove-btn"
@click.stop="deleteFilter(filter, i)"
>
mdi-close-box
</v-icon>
<span v-else :key="`${i}_1`" />
<v-select
v-model="filter.logical_op"
class="flex-shrink-1 flex-grow-0 elevation-0 caption"
:items="['and', 'or']"
solo
flat
dense
hide-details
placeholder="Group op"
@click.stop
@change="saveOrUpdate(filter, i)"
>
<template #item="{ item }">
<span class="caption font-weight-regular">{{ item }}</span>
</template>
</v-select>
</div>
<column-filter
v-if="filter.id || shared"
ref="nestedFilter"
v-model="filter.children"
:parent-id="filter.id"
:view-id="viewId"
nested
:meta="meta"
:shared="shared"
:web-hook="webHook"
:hook-id="hookId"
@updated="$emit('updated')"
@input="$emit('input', filters)"
/>
</div>
<template v-else>
<v-icon
v-if="!filter.readOnly"
:key="`${i}_3`"
small
class="nc-filter-item-remove-btn"
@click.stop="deleteFilter(filter, i)"
>
mdi-close-box
</v-icon>
<span v-else :key="`${i}_1`" />
<span v-if="!i" :key="`${i}_2`" class="caption d-flex align-center">{{ $t('labels.where') }}</span>
<v-select
v-else
:key="`${i}_4`"
v-model="filter.logical_op"
class="flex-shrink-1 flex-grow-0 elevation-0 caption"
:items="['and', 'or']"
solo
flat
dense
hide-details
:disabled="filter.readOnly"
@click.stop
@change="filterUpdateCondition(filter, i)"
>
<template #item="{ item }">
<span class="caption font-weight-regular">{{ item }}</span>
</template>
</v-select>
<FieldListAutoCompleteDropdown
:key="`${i}_6`"
v-model="filter.fk_column_id"
class="caption nc-filter-field-select"
:columns="columns"
:disabled="filter.readOnly"
@click.stop
@change="saveOrUpdate(filter, i)"
/>
<v-select
:key="`k${i}`"
v-model="filter.comparison_op"
class="flex-shrink-1 flex-grow-0 caption nc-filter-operation-select"
:items="filterComparisonOp(filter)"
:placeholder="$t('labels.operation')"
solo
flat
style="max-width: 120px"
dense
:disabled="filter.readOnly"
hide-details
item-value="value"
@click.stop
@change="filterUpdateCondition(filter, i)"
>
<template #item="{ item }">
<span class="caption font-weight-regular">{{ item.text }}</span>
</template>
</v-select>
<span v-if="['null', 'notnull', 'empty', 'notempty'].includes(filter.comparison_op)" :key="`span${i}`" />
<v-checkbox
v-else-if="types[filter.field] === 'boolean'"
:key="`${i}_7`"
v-model="filter.value"
dense
:disabled="filter.readOnly"
@change="saveOrUpdate(filter, i)"
/>
<v-text-field
v-else
:key="`${i}_7`"
v-model="filter.value"
solo
flat
hide-details
dense
class="caption nc-filter-value-select"
:disabled="filter.readOnly"
@click.stop
@input="saveOrUpdate(filter, i)"
/>
</template>
</template>
</template>
</div>
<v-btn small class="elevation-0 grey&#45;&#45;text my-3" @click.stop="addFilter">
<v-icon small color="grey"> mdi-plus </v-icon>
&lt;!&ndash; Add Filter &ndash;&gt;
{{ $t('activity.addFilter') }}
</v-btn>
<slot />
</div> -->
</template>
<style scoped>

75
packages/nc-gui-v2/components/smartsheet-toolbar/ColumnFilterMenu.vue

@ -2,7 +2,6 @@
// todo: move to persisted state
import { useState } from '#app'
import { IsLockedInj } from '~/components'
import Smartsheet from '~/components/tabs/Smartsheet.vue'
import MdiFilterIcon from '~icons/mdi/filter-outline'
import MdiMenuDownIcon from '~icons/mdi/menu-down'
@ -14,58 +13,6 @@ const filters = []
// todo: implement
const applyChanges = () => {}
/* import ColumnFilter from '~/components/project/spreadsheet/components/ColumnFilter'
export default {
name: 'ColumnFilterMenu',
components: { ColumnFilter },
props: ['fieldList', 'isLocked', 'value', 'meta', 'viewId', 'shared'],
data: () => ({
filters: [],
}),
computed: {
autosave: {
set(v) {
this.$store.commit('settings/MutAutoApplyFilter', v)
this.$e('a:filter:auto-apply', { flag: v })
},
get() {
return this.$store.state.settings.autoApplyFilter
},
},
},
watch: {
filters: {
handler(v) {
if (this.autosave) {
this.$emit('input', v)
}
},
deep: true,
},
autosave(v) {
if (!v) {
this.filters = JSON.parse(JSON.stringify(this.value || []))
}
},
value(v) {
this.filters = this.autosave ? v || [] : JSON.parse(JSON.stringify(v || []))
},
},
created() {
this.filters = this.autosave ? this.value || [] : JSON.parse(JSON.stringify(this.value || []))
},
methods: {
applyChanges() {
this.$emit('input', this.filters)
if (this.$refs.filter) {
this.$refs.filter.applyChanges()
}
this.$e('a:filter:apply')
},
},
} */
</script>
<template>
@ -92,15 +39,7 @@ export default {
</v-badge>
</template>
<SmartsheetToolbarColumnFilter>
<!--
v-model="filters"
:shared="shared"
:view-id="viewId"
:field-list="fieldList"
:meta="meta" -->
<!-- v-on="$listeners" -->
<div class="d-flex align-center mx-2" @click.stop>
<!-- <div class="d-flex align-center mx-2" @click.stop>
<v-checkbox
id="col-filter-checkbox"
v-model="autoApplyFilter"
@ -111,22 +50,16 @@ export default {
color="grey"
>
<template #label>
<span class="grey--text caption">
<span class="grey&#45;&#45;text caption">
{{ $t('msg.info.filterAutoApply') }}
<!-- Auto apply -->
&lt;!&ndash; Auto apply &ndash;&gt;
</span>
</template>
</v-checkbox>
<v-spacer />
<v-btn v-show="!autoApplyFilter" color="primary" small class="caption ml-2" @click="applyChanges"> Apply changes </v-btn>
</div>
</div> -->
</SmartsheetToolbarColumnFilter>
</v-menu>
</template>
<style scoped>
/*/deep/ .col-filter-checkbox .v-input--selection-controls__input {
transform: scale(0.7);
}*/
</style>

160
packages/nc-gui-v2/components/smartsheet-toolbar/SortListMenu.vue

@ -23,101 +23,6 @@ watch(
},
{ immediate: true },
)
/* import { RelationTypes, UITypes } from 'nocodb-sdk'
import { getUIDTIcon } from '~/components/project/spreadsheet/helpers/uiTypes'
import FieldListAutoCompleteDropdown from '~/components/project/spreadsheet/components/FieldListAutoCompleteDropdown'
export default {
name: 'SortListMenu',
components: { FieldListAutoCompleteDropdown },
props: {
fieldList: Array,
value: [Array, Object],
isLocked: Boolean,
meta: [Object],
viewId: String,
shared: Boolean,
},
data: () => ({
sortList: [],
}),
computed: {
columns() {
if (!this.meta || !this.meta.columns) {
return []
}
return this.meta.columns
.filter((c) => !(c.uidt === UITypes.LinkToAnotherRecord && c.colOptions.type !== RelationTypes.BELONGS_TO))
.map((c) => ({
...c,
icon: getUIDTIcon(c.uidt),
}))
},
},
watch: {
value(v) {
this.sortList = v || []
},
async viewId(v) {
if (v) {
await this.loadSortList()
}
},
},
async created() {
this.sortList = this.value || []
this.loadSortList()
},
methods: {
addSort() {
this.sortList.push({
fk_column_id: null,
direction: 'asc',
})
this.sortList = this.sortList.slice()
this.$e('a:sort:add', { length: this.sortList.length })
},
async loadSortList() {
if (!this.shared) {
// && !this._isUIAllowed('sortSync')) {
let sortList = []
if (this.viewId) {
const data = await this.$api.dbTableSort.list(this.viewId)
sortList = data.sorts.list
}
this.sortList = sortList
}
},
async saveOrUpdate(sort, i) {
if (!this.shared && this._isUIAllowed('sortSync')) {
if (sort.id) {
await this.$api.dbTableSort.update(sort.id, sort)
} else {
this.$set(this.sortList, i, await this.$api.dbTableSort.create(this.viewId, sort))
}
} else {
this.$emit('input', this.sortList)
}
this.$emit('updated')
this.$e('a:sort:dir', { direction: sort.direction })
},
async deleteSort(sort, i) {
if (!this.shared && sort.id && this._isUIAllowed('sortSync')) {
await this.$api.dbTableSort.delete(sort.id)
await this.loadSortList()
} else {
this.sortList.splice(i, 1)
this.$emit('input', this.sortList)
}
this.$emit('updated')
this.$e('a:sort:delete')
},
},
} */
</script>
<template>
@ -183,71 +88,6 @@ export default {
</v-btn>
</div>
</v-menu>
<!-- <v-menu offset-y transition="slide-y-transition">
<template #activator="{ on }">
<v-badge :value="sortList && sortList.length" color="primary" dot overlap>
<v-btn
v-t="['c:sort']"
class="nc-sort-menu-btn px-2 nc-remove-border"
:disabled="isLocked"
small
text
outlined
:class="{
'primary lighten-5 grey&#45;&#45;text text&#45;&#45;darken-3': sortList && sortList.length,
}"
v-on="on"
>
<v-icon small class="mr-1" color="#777"> mdi-sort </v-icon>
&lt;!&ndash; Sort &ndash;&gt;
{{ $t('activity.sort') }}
<v-icon small color="#777"> mdi-menu-down </v-icon>
</v-btn>
</v-badge>
</template>
<div class="backgroundColor pa-2 menu-filter-dropdown" style="min-width: 330px">
<div class="sort-grid" @click.stop>
<template v-for="(sort, i) in sortList || []" dense>
<v-icon :key="`${i}icon`" class="nc-sort-item-remove-btn" small @click.stop="deleteSort(sort)"> mdi-close-box </v-icon>
<FieldListAutoCompleteDropdown
:key="`${i}sel1`"
v-model="sort.fk_column_id"
class="caption nc-sort-field-select"
:columns="columns"
@click.stop
@change="saveOrUpdate(sort, i)"
/>
<v-select
:key="`${i}sel2`"
v-model="sort.direction"
class="flex-shrink-1 flex-grow-0 caption nc-sort-dir-select"
:items="[
{ text: 'A -> Z', value: 'asc' },
{ text: 'Z -> A', value: 'desc' },
]"
:label="$t('labels.operation')"
solo
flat
dense
hide-details
@click.stop
@change="saveOrUpdate(sort, i)"
>
<template #item="{ item }">
<span class="caption font-weight-regular">{{ item.text }}</span>
</template>
</v-select>
</template>
</div>
<v-btn small class="elevation-0 grey&#45;&#45;text my-3" @click.stop="addSort">
<v-icon small color="grey"> mdi-plus </v-icon>
&lt;!&ndash; Add Sort Option &ndash;&gt;
{{ $t('activity.addSort') }}
</v-btn>
</div>
</v-menu> -->
</template>
<style scoped>

2
packages/nc-gui-v2/utils/filterUtils.ts

@ -1,4 +1,4 @@
export const comparisonOp = [
export const comparisonOpList = [
{
text: 'is equal',
value: 'eq',

Loading…
Cancel
Save