Browse Source

feat(gui-v2): add column menu and edit column option

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2857/head
Pranav C 2 years ago
parent
commit
1f74777001
  1. 3
      packages/nc-gui-v2/assets/style-v2.scss
  2. 161
      packages/nc-gui-v2/components/smartsheet-column/AdvancedOptions.vue
  3. 83
      packages/nc-gui-v2/components/smartsheet-column/Edit.vue
  4. 5
      packages/nc-gui-v2/components/smartsheet-header/Cell.vue
  5. 42
      packages/nc-gui-v2/components/smartsheet-header/Menu.vue
  6. 7
      packages/nc-gui-v2/composables/useProject.ts
  7. 189
      packages/nc-gui-v2/utils/columnUtils.ts

3
packages/nc-gui-v2/assets/style-v2.scss

@ -72,9 +72,8 @@ html {
overflow-y: auto !important;
}
.nc-menu-item {
@apply cursor-pointer text-xs flex align-center gap-2 p-4 relative after:(content-[''] absolute top-0 left-0 w-full h-full right 0 bg-current opacity-0 transition transition-opactity duration-100) hover:(after:(opacity-5));
@apply cursor-pointer text-xs flex align-center gap-2 px-4 py-3 relative after:(content-[''] absolute top-0 left-0 w-full h-full right 0 bg-current opacity-0 transition transition-opactity duration-100) hover:(after:(opacity-5));
}
.nc-sidebar-right-item {

161
packages/nc-gui-v2/components/smartsheet-column/AdvancedOptions.vue

@ -0,0 +1,161 @@
<script setup lang="ts">
import useProject from "~/composables/useProject";
const {sqlUi} = useProject()
// const dataTypes = computed(() => sqlUi?.value?.getDataTypeListForUiType(this.newColumn, this.idType)
</script>
<template>
<div class="p-4 border-[2px] radius-1 border-grey w-full">
<div class="flex justify-space-between">
<a-form-item label="NN" :label-col="2">
<a-checkbox size="small" class="nc-column-name-input"/>
</a-form-item>
<a-form-item label="PK">
<a-checkbox size="small" class="nc-column-name-input"/>
</a-form-item>
<a-form-item label="AI">
<a-checkbox size="small" class="nc-column-name-input"/>
</a-form-item>
<a-form-item label="UN">
<a-checkbox size="small" class="nc-column-name-input"/>
</a-form-item>
<a-form-item label="AU">
<a-checkbox size="small" class="nc-column-name-input"/>
</a-form-item>
</div>
<!-- <a-form-item :label="$t('labels.databaseType')">
<a-select size="small" class="nc-column-name-input">
<a-select-option v-for="opt in dataTypes" :key="opt.name" :value="opt.name">
<div class="flex gap-1 align-center text-xs">
<component :is="opt.icon" class="text-grey" />
{{ opt.name }}
</div>
</a-select-option>
</a-select>
</a-form-item>-->
<!-- <div class="d-flex justify-space-between caption">
<v-checkbox
v-model="newColumn.rqd"
:disabled="newColumn.pk || !sqlUi.columnEditable(newColumn)"
class="mr-2 mt-0"
dense
hide-details
label="NN"
@change="newColumn.altered = newColumn.altered || 2"
>
<template #label>
<span class="caption font-weight-bold">NN</span>
</template>
</v-checkbox>
<v-checkbox
v-model="newColumn.pk"
:disabled="!sqlUi.columnEditable(newColumn)"
class="mr-2 mt-0"
dense
hide-details
label="PK"
@change="newColumn.altered = newColumn.altered || 2"
>
<template #label>
<span class="caption font-weight-bold">PK</span>
</template>
</v-checkbox>
<v-checkbox
v-model="newColumn.ai"
:disabled="sqlUi.colPropUNDisabled(newColumn) || !sqlUi.columnEditable(newColumn)"
class="mr-2 mt-0"
dense
hide-details
label="AI"
@change="newColumn.altered = newColumn.altered || 2"
>
<template #label>
<span class="caption font-weight-bold">AI</span>
</template>
</v-checkbox>
<v-checkbox
v-model="newColumn.un"
class="mr-2 mt-0"
dense
hide-details
label="UN"
:disabled="sqlUi.colPropUNDisabled(newColumn) || !sqlUi.columnEditable(newColumn)"
@change="newColumn.altered = newColumn.altered || 2"
>
<template #label>
<span class="caption font-weight-bold">UN</span>
</template>
</v-checkbox>
<v-checkbox
v-model="newColumn.au"
class="mr-2 mt-0"
dense
hide-details
label="UN"
:disabled="sqlUi.colPropAuDisabled(newColumn) || !sqlUi.columnEditable(newColumn)"
@change="newColumn.altered = newColumn.altered || 2"
>
<template #label>
<span class="caption font-weight-bold">AU</span>
</template>
</v-checkbox>
&lt;!&ndash; label="Type in Database" &ndash;&gt;
<v-autocomplete
v-model="newColumn.dt"
hide-details
class="caption data-type"
:label="$t('labels.databaseType')"
dense
outlined
:items="dataTypes"
@change="onDataTypeChange"
/>
&lt;!&ndash; label="Length / Values" &ndash;&gt;
<v-text-field
v-if="!isSelect"
v-model="newColumn.dtxp"
dense
:disabled="sqlUi.getDefaultLengthIsDisabled(newColumn.dt) || !sqlUi.columnEditable(newColumn)"
class="caption"
:label="$t('labels.lengthValue')"
outlined
hide-details
@input="newColumn.altered = newColumn.altered || 2"
/>
<v-text-field
v-model="newColumn.dtxs"
dense
:disabled="!sqlUi.columnEditable(newColumn)"
class="caption"
label="Scale"
outlined
hide-details
@input="newColumn.altered = newColumn.altered || 2"
/>
<v-textarea
v-model="newColumn.cdf"
:label="$t('placeholder.defaultValue')"
:hint="sqlUi.getDefaultValueForDatatype(newColumn.dt)"
persistent-hint
rows="3"
outlined
dense
class="caption"
@input="
newColumn.altered = newColumn.altered || 2
newColumn.cdf = newColumn.cdf || null
"
/>
</div>-->
</div>
</template>
<style scoped></style>

83
packages/nc-gui-v2/components/smartsheet-column/Edit.vue

@ -0,0 +1,83 @@
<script lang="ts" setup>
import { computed, inject } from '#imports'
import Smartsheet from '~/components/tabs/Smartsheet.vue'
import { MetaInj } from '~/context'
import { uiTypes } from '~/utils/columnUtils'
import MdiPlusIcon from '~icons/mdi/plus-circle-outline'
import MdiMinusIcon from '~icons/mdi/minus-circle-outline'
const meta = inject(MetaInj)
const advancedOptions = ref(false)
// todo: make as a prop
const editColumn = null
const uiTypesOptions = computed<typeof uiTypes>(() => {
return [
...uiTypes.filter((t) => !editColumn || !t.virtual),
...(!editColumn && meta?.value?.columns?.every((c) => !c.pk)
? [
{
name: 'ID',
icon: 'mdi-identifier',
},
]
: []),
]
})
</script>
<template>
<div class="max-w-[300px] min-w-[300px] max-h-[95vh] bg-white shadow p-4" @click.stop>
<a-form layout="vertical">
<a-form-item :label="$t('labels.columnName')">
<a-input size="small" class="nc-column-name-input" />
</a-form-item>
<a-form-item :label="$t('labels.columnType')">
<a-select size="small" class="nc-column-name-input">
<a-select-option v-for="opt in uiTypesOptions" :key="opt.name" :value="opt.name">
<div class="flex gap-1 align-center text-xs">
<component :is="opt.icon" class="text-grey" />
{{ opt.name }}
</div>
</a-select-option>
</a-select>
</a-form-item>
<div>
<div
class="text-xs cursor-pointer text-grey nc-more-options my-2 flex align-center gap-1 justify-end"
@click="advancedOptions = !advancedOptions"
>
{{ advancedOptions ? $t('general.hideAll') : $t('general.showMore') }}
<component :is="advancedOptions ? MdiMinusIcon : MdiPlusIcon" />
</div>
</div>
<div class="overflow-hidden" :class="advancedOptions ? 'h-min' : 'h-0'">
<SmartsheetColumnAdvancedOptions />
</div>
</a-form>
</div>
</template>
<style scoped>
:deep(.ant-form-item-label > label) {
@apply !text-xs;
}
:deep(.ant-form-item-label) {
@apply !pb-0;
}
:deep(.ant-form-item-control-input) {
@apply !min-h-min;
}
:deep(.ant-form-item) {
@apply !mb-1;
}
:deep(.ant-select-selection-item) {
@apply flex align-center;
}
</style>

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

@ -70,13 +70,14 @@ export default {
</script>
<template>
<div class="d-flex align-center d-100">
<div class="flex align-center w-full">
<SmartsheetHeaderCellIcon v-if="column" />
<span v-if="column" class="name" style="white-space: nowrap" :title="column.title">{{ column.title }}</span>
<!-- <span v-if="(column.rqd && !column.cdf) || required" class="error&#45;&#45;text text&#45;&#45;lighten-1">&nbsp;*</span> -->
<v-spacer />
<div class="flex-1" />
<SmartsheetHeaderMenu />
<!-- todo: implement delete or edit column
<v-menu
v-if="!isLocked && !isPublicView && _isUIAllowed('edit-column') && !isForm"

42
packages/nc-gui-v2/components/smartsheet-header/Menu.vue

@ -0,0 +1,42 @@
<script lang="ts" setup>
import MdiEditIcon from '~icons/mdi/pencil'
import MdiStarIcon from '~icons/mdi/star'
import MdiDeleteIcon from '~icons/mdi/delete-outline'
import MdiMenuDownIcon from '~icons/mdi/menu-down'
const editCellDropdown = $ref(false)
</script>
<template>
<a-dropdown v-model:visible="editCellDropdown" :trigger="['click']">
<span />
<template #overlay>
<SmartsheetColumnEdit @click.stop />
</template>
</a-dropdown>
<a-dropdown :trigger="['hover']">
<MdiMenuDownIcon class="text-grey" />
<template #overlay>
<div class="shadow bg-white">
<div class="nc-column-edit nc-menu-item" @click="editCellDropdown = true">
<MdiEditIcon class="text-primary" />
<!-- Edit -->
{{ $t('general.edit') }}
</div>
<div v-t="['a:column:set-primary']" class="nc-menu-item">
<MdiStarIcon class="text-primary" />
<!-- todo : tooltip -->
<!-- Set as Primary value -->
{{ $t('activity.setPrimary') }}
<!-- <span class="caption font-weight-bold">Primary value will be shown in place of primary key</span> -->
</div>
<div class="nc-column-delete nc-menu-item">
<MdiDeleteIcon class="text-error" />
<!-- Delete -->
{{ $t('general.delete') }}
</div>
</div>
</template>
</a-dropdown>
</template>

7
packages/nc-gui-v2/composables/useProject.ts

@ -1,5 +1,5 @@
import { SqlUiFactory } from 'nocodb-sdk'
import type { ProjectType, TableType } from 'nocodb-sdk'
import type { OracleUi, ProjectType, TableType } from 'nocodb-sdk'
import type { MaybeRef } from '@vueuse/core'
import { useNuxtApp, useState } from '#app'
import { USER_PROJECT_ROLES } from '~/lib/constants'
@ -21,6 +21,7 @@ export default (projectId?: MaybeRef<string>) => {
projectRoles.value = user.roles
}
}
async function loadTables() {
if (project.value.id) {
const tablesResponse = await $api.dbTable.list(project.value.id)
@ -44,7 +45,9 @@ export default (projectId?: MaybeRef<string>) => {
const isMysql = computed(() => ['mysql', 'mysql2'].includes(projectBaseType))
const isPg = computed(() => projectBaseType === 'pg')
const sqlUi = computed(() => SqlUiFactory.create({ client: projectBaseType }))
const sqlUi = computed<ReturnType<typeof SqlUiFactory['create']>>(() =>
SqlUiFactory.create({ client: projectBaseType }),
)
return { project, tables, loadProjectRoles, loadProject, loadTables, isMysql, isPg, sqlUi }
}

189
packages/nc-gui-v2/utils/columnUtils.ts

@ -0,0 +1,189 @@
import { UITypes } from 'nocodb-sdk'
import LinkVariant from '~icons/mdi/link-variant'
import TableColumnPlusBefore from '~icons/mdi/table-column-plus-before'
import FormatColorText from '~icons/mdi/format-color-text'
import TextSubject from '~icons/mdi/text-subject'
import Attachment from '~icons/mdi/attachment'
import CheckboxMarkedOutline from '~icons/mdi/checkbox-marked-outline'
import FormatListBulletedSquare from '~icons/mdi/format-list-bulleted-square'
import ArrowDownDropCircle from '~icons/mdi/arrow-down-drop-circle'
import CalendarMonth from '~icons/mdi/calendar-month'
import Calendar from '~icons/mdi/calendar'
import Clock from '~icons/mdi/clock'
import FilePhone from '~icons/mdi/file-phone'
import Email from '~icons/mdi/email'
import Web from '~icons/mdi/web'
import Numeric from '~icons/mdi/numeric'
import Decimal from '~icons/mdi/decimal'
import CurrencyUsdCircleOutline from '~icons/mdi/currency-usd-circle-outline'
import PercentOutline from '~icons/mdi/percent-outline'
import TimerOutline from '~icons/mdi/timer-outline'
import Star from '~icons/mdi/star'
import MathIntegral from '~icons/mdi/math-integral'
import MovieRoll from '~icons/mdi/movie-roll'
import Counter from '~icons/mdi/counter'
import CalendarClock from '~icons/mdi/calendar-clock'
const uiTypes = [
{
name: UITypes.LinkToAnotherRecord,
icon: LinkVariant,
virtual: 1,
},
{
name: UITypes.Lookup,
icon: TableColumnPlusBefore,
virtual: 1,
},
{
name: UITypes.SingleLineText,
icon: FormatColorText,
},
{
name: UITypes.LongText,
icon: TextSubject,
},
{
name: UITypes.Attachment,
icon: Attachment,
},
{
name: UITypes.Checkbox,
icon: CheckboxMarkedOutline,
},
{
name: UITypes.MultiSelect,
icon: FormatListBulletedSquare,
},
{
name: UITypes.SingleSelect,
icon: ArrowDownDropCircle,
},
{
name: UITypes.Date,
icon: CalendarMonth,
},
{
name: UITypes.Year,
icon: Calendar,
},
{
name: UITypes.Time,
icon: Clock,
},
{
name: UITypes.PhoneNumber,
icon: FilePhone,
},
{
name: UITypes.Email,
icon: Email,
},
{
name: UITypes.URL,
icon: Web,
},
{
name: UITypes.Number,
icon: Numeric,
},
{
name: UITypes.Decimal,
icon: Decimal,
},
{
name: UITypes.Currency,
icon: CurrencyUsdCircleOutline,
},
{
name: UITypes.Percent,
icon: PercentOutline,
},
{
name: UITypes.Duration,
icon: TimerOutline,
},
{
name: UITypes.Rating,
icon: Star,
},
{
name: UITypes.Formula,
icon: MathIntegral,
virtual: 1,
},
{
name: UITypes.Rollup,
icon: MovieRoll,
virtual: 1,
},
{
name: UITypes.Count,
icon: Counter,
},
{
name: UITypes.DateTime,
icon: CalendarClock,
},
{
name: UITypes.AutoNumber,
icon: Numeric,
},
{
name: UITypes.Geometry,
icon: 'mdi-ruler-square-compass',
},
{
name: UITypes.JSON,
icon: 'mdi-code-json',
},
{
name: UITypes.SpecificDBType,
icon: 'mdi-database-settings',
},
]
const getUIDTIcon = (uidt: UITypes) => {
return (
[
...uiTypes,
{
name: UITypes.CreateTime,
icon: 'mdi-calendar-clock',
},
{
name: UITypes.ID,
icon: 'mdi-identifier',
},
{
name: UITypes.ForeignKey,
icon: 'mdi-link-variant',
},
].find((t) => t.name === uidt) || {}
).icon
}
export { uiTypes, getUIDTIcon }
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
Loading…
Cancel
Save