Browse Source

Merge pull request #3114 from nocodb/refactor/gui-v2-column-header-ui

refactor: gui v2 column header UI and nocodb logo
pull/3082/head
navi 2 years ago committed by GitHub
parent
commit
cdd7cc1561
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      packages/nc-gui-v2/components.d.ts
  2. 61
      packages/nc-gui-v2/components/dashboard/TreeView.vue
  3. 2
      packages/nc-gui-v2/components/dashboard/settings/AppStore.vue
  4. 16
      packages/nc-gui-v2/components/smartsheet-column/AdvancedOptions.vue
  5. 30
      packages/nc-gui-v2/components/smartsheet-column/CheckboxOptions.vue
  6. 4
      packages/nc-gui-v2/components/smartsheet-column/CurrencyOptions.vue
  7. 2
      packages/nc-gui-v2/components/smartsheet-column/DateOptions.vue
  8. 2
      packages/nc-gui-v2/components/smartsheet-column/DurationOptions.vue
  9. 80
      packages/nc-gui-v2/components/smartsheet-column/EditOrAdd.vue
  10. 22
      packages/nc-gui-v2/components/smartsheet-column/LinkedToAnotherRecordOptions.vue
  11. 16
      packages/nc-gui-v2/components/smartsheet-column/LookupOptions.vue
  12. 6
      packages/nc-gui-v2/components/smartsheet-column/PercentOptions.vue
  13. 34
      packages/nc-gui-v2/components/smartsheet-column/RatingOptions.vue
  14. 18
      packages/nc-gui-v2/components/smartsheet-column/RollupOptions.vue
  15. 2
      packages/nc-gui-v2/components/smartsheet-column/SpecificDBTypeOptions.vue
  16. 28
      packages/nc-gui-v2/components/smartsheet-header/Cell.vue
  17. 24
      packages/nc-gui-v2/components/smartsheet-header/Menu.vue
  18. 28
      packages/nc-gui-v2/components/smartsheet-header/VirtualCell.vue
  19. 8
      packages/nc-gui-v2/components/smartsheet/Grid.vue
  20. 6
      packages/nc-gui-v2/components/smartsheet/Toolbar.vue
  21. 46
      packages/nc-gui-v2/components/tabs/Auth.vue
  22. 2
      packages/nc-gui-v2/components/tabs/auth/ApiTokenManagement.vue
  23. 2
      packages/nc-gui-v2/components/tabs/auth/UserManagement.vue
  24. 2
      packages/nc-gui-v2/layouts/base.vue
  25. 4
      packages/nc-gui-v2/pages/nc/[projectId]/index.vue
  26. 35
      packages/nc-gui-v2/pages/nc/[projectId]/index/index.vue

5
packages/nc-gui-v2/components.d.ts vendored

@ -110,6 +110,8 @@ declare module '@vue/runtime-core' {
MdiInformation: typeof import('~icons/mdi/information')['default']
MdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
MdiKeyStar: typeof import('~icons/mdi/key-star')['default']
MdiLens: typeof import('~icons/mdi/lens')['default']
MdiLense: typeof import('~icons/mdi/lense')['default']
MdiLink: typeof import('~icons/mdi/link')['default']
MdiLinkVariantRemove: typeof import('~icons/mdi/link-variant-remove')['default']
MdiLogout: typeof import('~icons/mdi/logout')['default']
@ -136,6 +138,9 @@ declare module '@vue/runtime-core' {
MdiTrashCan: typeof import('~icons/mdi/trash-can')['default']
MdiWhatsapp: typeof import('~icons/mdi/whatsapp')['default']
MdiXml: typeof import('~icons/mdi/xml')['default']
MdiZomm: typeof import('~icons/mdi/zomm')['default']
MdiZoom: typeof import('~icons/mdi/zoom')['default']
MdiZoomIn: typeof import('~icons/mdi/zoom-in')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}

61
packages/nc-gui-v2/components/dashboard/TreeView.vue

@ -1,15 +1,14 @@
<script setup lang="ts">
import type { TableType } from 'nocodb-sdk'
import Sortable from 'sortablejs'
import { Empty } from 'ant-design-vue'
import { useNuxtApp, useRoute } from '#app'
import { computed, useProject, useTable, useTabs, watchEffect } from '#imports'
import { TabType } from '~/composables'
import MdiView from '~icons/mdi/eye-circle-outline'
import MdiTableLarge from '~icons/mdi/table-large'
import MdiMenuDown from '~icons/mdi/chevron-down'
import MdiMenuIcon from '~icons/mdi/dots-vertical'
import MdiDrag from '~icons/mdi/drag-vertical'
import MdiPlus from '~icons/mdi/plus-circle-outline'
const { addTab } = useTabs()
@ -28,7 +27,6 @@ const tablesById = $computed<Record<string, TableType>>(() =>
}, {}),
)
const showTableList = ref(true)
const tableCreateDlg = ref(false)
let key = $ref(0)
@ -135,13 +133,15 @@ const activeTable = computed(() => {
<template>
<div class="nc-treeview-container flex flex-col">
<div class="px-6 py-[11.75px] border-b-1">
<a-input-search
v-model:value="filterQuery"
size="small"
class="nc-filter-input"
:placeholder="$t('placeholder.searchProjectTree')"
/>
<div class="px-6 py-[8.75px] border-b-1 nc-filter-input">
<div class="flex items-center bg-gray-50 rounded relative">
<a-input
v-model:value="filterQuery"
class="nc-filter-input !bg-transparent"
:placeholder="$t('placeholder.searchProjectTree')"
/>
<MdiSearch class="nc-filter-input-icon text-gray-400 mx-3 absolute right-[-4px] top-[7px]" />
</div>
</div>
<a-dropdown :trigger="['contextmenu']">
@ -149,7 +149,6 @@ const activeTable = computed(() => {
<div
style="direction: ltr"
class="py-1 px-3 flex w-full align-center gap-1 cursor-pointer"
@click="showTableList = !showTableList"
@contextmenu="setMenuContext('main')"
>
<span class="flex-grow text-bold uppercase nc-project-tree text-gray-500 font-weight-bold">
@ -157,24 +156,9 @@ const activeTable = computed(() => {
<template v-if="tables?.length"> ({{ tables.length }}) </template>
</span>
<MdiPlus
v-t="['c:table:create:navdraw']"
class="transform text-gray-500 hover:(text-pink-500 scale-105) nc-btn-tbl-add"
@click.stop="tableCreateDlg = true"
/>
<MdiMenuDown
class="transition-transform !duration-100 text-gray-500 hover:text-pink-500"
:class="{ 'transform rotate-180': showTableList }"
/>
</div>
<div style="direction: ltr" class="flex-1">
<div
v-if="tables.length"
class="transition-height duration-200 overflow-hidden"
:class="{ 'h-100': showTableList, 'h-0': !showTableList }"
>
<div v-if="tables.length" class="transition-height duration-200 overflow-hidden">
<div :key="key" ref="menuRef" class="border-none sortable-list">
<div
v-for="table of tables"
@ -207,7 +191,9 @@ const activeTable = computed(() => {
<template #overlay>
<a-menu class="cursor-pointer">
<a-menu-item v-t="" class="!text-xs" @click="showRenameTableDlg(table)"><div>Rename</div></a-menu-item>
<a-menu-item v-t="" class="!text-xs" @click="showRenameTableDlg(table)">
<div>Rename</div>
</a-menu-item>
<a-menu-item class="!text-xs" @click="deleteTable(table)"> Delete</a-menu-item>
</a-menu>
@ -217,6 +203,14 @@ const activeTable = computed(() => {
</div>
</div>
</div>
<a-card v-else class="mt-4 mx-4 !bg-gray-50">
<div class="flex flex-col align-center">
<a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" />
<a-button type="primary" @click.stop="tableCreateDlg = true">{{ $t('tooltip.addTable') }}</a-button>
</div>
</a-card>
</div>
</div>
@ -244,7 +238,7 @@ const activeTable = computed(() => {
</div>
</template>
<style scoped>
<style scoped lang="scss">
.nc-treeview-container {
@apply h-[calc(100vh_-_var(--header-height))];
}
@ -271,7 +265,7 @@ const activeTable = computed(() => {
@apply !pointer-events-none;
}
&.dragging {
& .dragging {
.nc-icon {
@apply !hidden;
}
@ -300,6 +294,7 @@ const activeTable = computed(() => {
.nc-tree-item.active {
@apply !text-primary font-weight-bold after:(!opacity-20);
svg {
@apply !text-primary;
}
@ -308,4 +303,10 @@ const activeTable = computed(() => {
.nc-tree-item:hover {
@apply !text-grey after:(!opacity-5);
}
:deep(.nc-filter-input) {
.ant-input {
@apply pr-6 !border-0;
}
}
</style>

2
packages/nc-gui-v2/components/dashboard/settings/AppStore.vue

@ -110,7 +110,7 @@ onMounted(async () => {
<div class="flex ml-0.5">Reset</div>
</div>
</a-button>
<a-button v-else size="small" outlined @click="showInstallPluginModal(app)">
<a-button v-else size="small" outlined type="primary" ghost @click="showInstallPluginModal(app)">
<div class="flex flex-row justify-center items-center caption capitalize nc-app-store-card-install">
<MdiPlusIcon />
Install

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

@ -16,13 +16,12 @@ formState.value.au = !!formState.value.au
</script>
<template>
<div class="p-4 border-[2px] radius-1 border-grey w-full">
<div class="p-4 border-[2px] radius-1 border-grey w-full flex flex-col gap-2">
<div class="flex justify-space-between">
<a-form-item label="NN">
<a-checkbox
v-model:checked="formState.rqd"
:disabled="formState.pk || !sqlUi.columnEditable(formState)"
size="small"
class="nc-column-checkbox-NN"
@change="onAlter"
/>
@ -31,7 +30,6 @@ formState.value.au = !!formState.value.au
<a-checkbox
v-model:checked="formState.pk"
:disabled="!sqlUi.columnEditable(formState)"
size="small"
class="nc-column-checkbox-PK"
@change="onAlter"
/>
@ -40,7 +38,6 @@ formState.value.au = !!formState.value.au
<a-checkbox
v-model:checked="formState.ai"
:disabled="sqlUi.colPropUNDisabled(formState) || !sqlUi.columnEditable(formState)"
size="small"
class="nc-column-checkbox-AI"
@change="onAlter"
/>
@ -50,18 +47,18 @@ formState.value.au = !!formState.value.au
:disabled="sqlUi.colPropUNDisabled(formState) || !sqlUi.columnEditable(formState)"
@change="onAlter"
>
<a-checkbox v-model:checked="formState.un" size="small" class="nc-column-checkbox-UN" />
<a-checkbox v-model:checked="formState.un" class="nc-column-checkbox-UN" />
</a-form-item>
<a-form-item
label="AU"
:disabled="sqlUi.colPropAuDisabled(formState) || !sqlUi.columnEditable(formState)"
@change="onAlter"
>
<a-checkbox v-model:checked="formState.au" size="small" class="nc-column-checkbox-AU" />
<a-checkbox v-model:checked="formState.au" class="nc-column-checkbox-AU" />
</a-form-item>
</div>
<a-form-item :label="$t('labels.databaseType')" v-bind="validateInfos.dt">
<a-select v-model:value="formState.dt" size="small" @change="onDataTypeChange">
<a-select v-model:value="formState.dt" @change="onDataTypeChange">
<a-select-option v-for="type in dataTypes" :key="type" :value="type">
{{ type }}
</a-select-option>
@ -71,15 +68,14 @@ formState.value.au = !!formState.value.au
<a-input
v-model:value="formState.dtxp"
:disabled="sqlUi.getDefaultLengthIsDisabled(formState.dt) || !sqlUi.columnEditable(formState)"
size="small"
@input="onAlter"
/>
</a-form-item>
<a-form-item v-if="sqlUi.showScale(formState)" label="Scale">
<a-input v-model="formState.dtxs" :disabled="!sqlUi.columnEditable(formState)" size="small" @input="onAlter" />
<a-input v-model="formState.dtxs" :disabled="!sqlUi.columnEditable(formState)" @input="onAlter" />
</a-form-item>
<a-form-item :label="$t('placeholder.defaultValue')">
<a-textarea v-model:value="formState.cdf" size="small" auto-size @input="onAlter(2, true)" />
<a-textarea v-model:value="formState.cdf" auto-size @input="onAlter(2, true)" />
<span class="text-gray-400 text-xs">{{ sqlUi.getDefaultValueForDatatype(formState.dt) }}</span>
</a-form-item>
</div>

30
packages/nc-gui-v2/components/smartsheet-column/CheckboxOptions.vue

@ -73,21 +73,23 @@ watch(
<a-row>
<a-col :span="24">
<a-form-item label="Icon">
<a-select v-model:value="formState.meta.iconIdx" size="small" class="w-52">
<a-select v-model:value="formState.meta.iconIdx" class="w-52">
<a-select-option v-for="(icon, i) of iconList" :key="i" :value="i">
<component
:is="getMdiIcon(icon.checked)"
class="mx-1"
:style="{
color: formState.meta.color,
}"
/>
<component
:is="getMdiIcon(icon.unchecked)"
:style="{
color: formState.meta.color,
}"
/>
<div class="flex items-center">
<component
:is="getMdiIcon(icon.checked)"
class="mx-1"
:style="{
color: formState.meta.color,
}"
/>
<component
:is="getMdiIcon(icon.unchecked)"
:style="{
color: formState.meta.color,
}"
/>
</div>
</a-select-option>
</a-select>
</a-form-item>

4
packages/nc-gui-v2/components/smartsheet-column/CurrencyOptions.vue

@ -67,12 +67,11 @@ formState.value.meta = {
</script>
<template>
<a-row>
<a-row gutter="8">
<a-col :span="12">
<a-form-item v-bind="validateInfos['meta.currency_locale']" label="Currency Locale">
<a-select
v-model:value="formState.meta.currency_locale"
size="small"
class="w-52"
show-search
:filter-option="filterOption"
@ -91,7 +90,6 @@ formState.value.meta = {
class="w-52"
show-search
:filter-option="filterOption"
size="small"
:disabled="isMoney && isPg"
>
<a-select-option v-for="(currencyCode, i) of currencyList" :key="i" :value="currencyCode">

2
packages/nc-gui-v2/components/smartsheet-column/DateOptions.vue

@ -12,7 +12,7 @@ if (!formState.meta?.date_format) {
<template>
<a-form-item label="Date Format">
<a-select v-model:value="formState.meta.date_format" size="small">
<a-select v-model:value="formState.meta.date_format">
<a-select-option v-for="(format, i) of dateFormats" :key="i" :value="format">
<div class="flex flex-row items-center">
<div class="text-xs">

2
packages/nc-gui-v2/components/smartsheet-column/DurationOptions.vue

@ -25,7 +25,7 @@ formState.value.meta = {
</a-col>
<a-col :span="24">
<a-form-item label="Duration Format">
<a-select v-model:value="formState.meta.duration" size="small" class="w-52">
<a-select v-model:value="formState.meta.duration" class="w-52">
<a-select-option v-for="(duration, i) of durationOptionList" :key="i" :value="duration.id">
{{ duration.title }}
</a-select-option>

80
packages/nc-gui-v2/components/smartsheet-column/EditOrAdd.vue

@ -105,57 +105,51 @@ if (!formState.value?.column_name) {
</script>
<template>
<div class="min-w-[350px] w-max max-h-[95vh] bg-white shadow p-4 overflow-auto" @click.stop>
<div class="min-w-[400px] max-h-[95vh] bg-white shadow p-6 overflow-auto" @click.stop>
<a-form v-model="formState" name="column-create-or-edit" layout="vertical">
<a-form-item :label="$t('labels.columnName')" v-bind="validateInfos.title">
<a-input ref="antInput" v-model:value="formState.title" size="small" class="nc-column-name-input" @input="onAlter(8)" />
</a-form-item>
<a-form-item
v-if="!(editColumnDropdown && !!onlyNameUpdateOnEditColumns.find((col) => col === formState.uidt))"
:label="$t('labels.columnType')"
>
<a-select
v-model:value="formState.uidt"
show-search
size="small"
class="nc-column-type-input"
@change="onUidtOrIdTypeChange"
<div class="flex flex-col gap-2">
<a-form-item :label="$t('labels.columnName')" v-bind="validateInfos.title">
<a-input ref="antInput" v-model:value="formState.title" class="nc-column-name-input" @input="onAlter(8)" />
</a-form-item>
<a-form-item
v-if="!(editColumnDropdown && !!onlyNameUpdateOnEditColumns.find((col) => col === formState.uidt))"
:label="$t('labels.columnType')"
>
<a-select-option v-for="opt of uiTypesOptions" :key="opt.name" :value="opt.name" v-bind="validateInfos.uidt">
<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>
<SmartsheetColumnFormulaOptions v-if="formState.uidt === UITypes.Formula" ref="formulaOptionsRef" />
<SmartsheetColumnCurrencyOptions v-if="formState.uidt === UITypes.Currency" />
<SmartsheetColumnDurationOptions v-if="formState.uidt === UITypes.Duration" />
<SmartsheetColumnRatingOptions v-if="formState.uidt === UITypes.Rating" />
<SmartsheetColumnCheckboxOptions v-if="formState.uidt === UITypes.Checkbox" />
<SmartsheetColumnLookupOptions v-if="!editColumnDropdown && formState.uidt === UITypes.Lookup" />
<SmartsheetColumnDateOptions v-if="formState.uidt === UITypes.Date" />
<SmartsheetColumnRollupOptions v-if="!editColumnDropdown && formState.uidt === UITypes.Rollup" />
<SmartsheetColumnLinkedToAnotherRecordOptions
v-if="!editColumnDropdown && formState.uidt === UITypes.LinkToAnotherRecord"
/>
<SmartsheetColumnSpecificDBTypeOptions v-if="formState.uidt === UITypes.SpecificDBType" />
<SmartsheetColumnPercentOptions v-if="formState.uidt === UITypes.Percent" />
<SmartsheetColumnSelectOptions v-if="formState.uidt === UITypes.SingleSelect || formState.uidt === UITypes.MultiSelect" />
<a-select v-model:value="formState.uidt" show-search class="nc-column-type-input" @change="onUidtOrIdTypeChange">
<a-select-option v-for="opt of uiTypesOptions" :key="opt.name" :value="opt.name" v-bind="validateInfos.uidt">
<div class="flex gap-1 align-center">
<component :is="opt.icon" class="text-grey" />
{{ opt.name }}
</div>
</a-select-option>
</a-select>
</a-form-item>
<SmartsheetColumnFormulaOptions v-if="formState.uidt === UITypes.Formula" ref="formulaOptionsRef" />
<SmartsheetColumnCurrencyOptions v-if="formState.uidt === UITypes.Currency" />
<SmartsheetColumnDurationOptions v-if="formState.uidt === UITypes.Duration" />
<SmartsheetColumnRatingOptions v-if="formState.uidt === UITypes.Rating" />
<SmartsheetColumnCheckboxOptions v-if="formState.uidt === UITypes.Checkbox" />
<SmartsheetColumnLookupOptions v-if="!editColumnDropdown && formState.uidt === UITypes.Lookup" />
<SmartsheetColumnDateOptions v-if="formState.uidt === UITypes.Date" />
<SmartsheetColumnRollupOptions v-if="!editColumnDropdown && formState.uidt === UITypes.Rollup" />
<SmartsheetColumnLinkedToAnotherRecordOptions
v-if="!editColumnDropdown && formState.uidt === UITypes.LinkToAnotherRecord"
/>
<SmartsheetColumnSpecificDBTypeOptions v-if="formState.uidt === UITypes.SpecificDBType" />
<SmartsheetColumnPercentOptions v-if="formState.uidt === UITypes.Percent" />
<SmartsheetColumnSelectOptions v-if="formState.uidt === UITypes.SingleSelect || formState.uidt === UITypes.MultiSelect" />
</div>
<div
v-if="!isVirtualCol(formState.uidt)"
class="text-xs cursor-pointer text-grey nc-more-options my-2 flex align-center gap-1 justify-end"
class="text-xs cursor-pointer text-grey nc-more-options mb-1 mt-4 flex align-center gap-1 justify-end"
@click="advancedOptions = !advancedOptions"
>
{{ advancedOptions ? $t('general.hideAll') : $t('general.showMore') }}
<component :is="advancedOptions ? MdiMinusIcon : MdiPlusIcon" />
</div>
<div class="overflow-hidden" :class="advancedOptions ? 'h-min' : 'h-0'">
<div class="overflow-hidden" :class="advancedOptions ? 'h-min mb-2' : 'h-0'">
<a-checkbox
v-if="formState.meta && columnToValidate.includes(formState.uidt)"
v-model:checked="formState.meta.validate"
@ -169,11 +163,11 @@ if (!formState.value?.column_name) {
</div>
<a-form-item>
<div class="flex justify-end gap-1 mt-4">
<a-button html-type="button" size="small" @click="onCancel">
<a-button html-type="button" @click="onCancel">
<!-- Cancel -->
{{ $t('general.cancel') }}
</a-button>
<a-button html-type="submit" type="primary" size="small" @click="onSubmit">
<a-button html-type="submit" type="primary" @click="onSubmit">
<!-- Save -->
{{ $t('general.save') }}
</a-button>

22
packages/nc-gui-v2/components/smartsheet-column/LinkedToAnotherRecordOptions.vue

@ -41,7 +41,7 @@ const refTables = $computed(() => {
<template>
<div class="w-full flex flex-col mb-2 mt-4">
<div class="border-2 p-4">
<div class="border-2 p-6">
<a-form-item v-bind="validateInfos.type">
<a-radio-group v-model:value="formState.type" name="type" v-bind="validateInfos.type">
<a-radio value="hm">Has Many</a-radio>
@ -49,7 +49,7 @@ const refTables = $computed(() => {
</a-radio-group>
</a-form-item>
<a-form-item class="flex w-full pb-2 mt-4" :label="$t('labels.childTable')" v-bind="validateInfos.childId">
<a-select v-model:value="formState.childId" size="small" @change="onDataTypeChange">
<a-select v-model:value="formState.childId" @change="onDataTypeChange">
<a-select-option v-for="(table, index) in refTables" :key="index" :value="table.id">
{{ table.title }}
</a-select-option>
@ -65,29 +65,17 @@ const refTables = $computed(() => {
<component :is="advancedOptions ? MdiMinusIcon : MdiPlusIcon" />
</div>
<div v-if="advancedOptions" class="flex flex-col p-4 border-2 mt-2">
<div v-if="advancedOptions" class="flex flex-col p-6 gap-4 border-2 mt-2">
<div class="flex flex-row space-x-2">
<a-form-item class="flex w-1/2" :label="$t('labels.onUpdate')">
<a-select
v-model:value="formState.onUpdate"
:disabled="formState.virtual"
name="onUpdate"
size="small"
@change="onDataTypeChange"
>
<a-select v-model:value="formState.onUpdate" :disabled="formState.virtual" name="onUpdate" @change="onDataTypeChange">
<a-select-option v-for="(option, index) in onUpdateDeleteOptions" :key="index" :value="option">
{{ option }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item class="flex w-1/2" :label="$t('labels.onDelete')">
<a-select
v-model:value="formState.onDelete"
:disabled="formState.virtual"
name="onDelete"
size="small"
@change="onDataTypeChange"
>
<a-select v-model:value="formState.onDelete" :disabled="formState.virtual" name="onDelete" @change="onDataTypeChange">
<a-select-option v-for="(option, index) in onUpdateDeleteOptions" :key="index" :value="option">
{{ option }}
</a-select-option>

16
packages/nc-gui-v2/components/smartsheet-column/LookupOptions.vue

@ -52,15 +52,10 @@ const columns = $computed(() => {
</script>
<template>
<div class="p-4 w-full flex flex-col border-2 mb-2 mt-4">
<div class="p-6 w-full flex flex-col border-2 mb-2 mt-4">
<div class="w-full flex flex-row space-x-2">
<a-form-item class="flex w-1/2 pb-2" :label="$t('labels.childTable')" v-bind="validateInfos.fk_relation_column_id">
<a-select
v-model:value="formState.fk_relation_column_id"
size="small"
dropdown-class-name="!w-64"
@change="onDataTypeChange"
>
<a-select v-model:value="formState.fk_relation_column_id" dropdown-class-name="!w-64" @change="onDataTypeChange">
<a-select-option v-for="(table, index) in refTables" :key="index" :value="table.col.fk_column_id">
<div class="flex flex-row space-x-0.5 h-full pb-0.5 items-center justify-between">
<div class="font-semibold text-xs">{{ table.column.title }}</div>
@ -72,12 +67,7 @@ const columns = $computed(() => {
</a-select>
</a-form-item>
<a-form-item class="flex w-1/2" :label="$t('labels.childColumn')" v-bind="validateInfos.fk_lookup_column_id">
<a-select
v-model:value="formState.fk_lookup_column_id"
name="fk_lookup_column_id"
size="small"
@change="onDataTypeChange"
>
<a-select v-model:value="formState.fk_lookup_column_id" name="fk_lookup_column_id" @change="onDataTypeChange">
<a-select-option v-for="(column, index) of columns" :key="index" :value="column.id">
{{ column.title }}
</a-select-option>

6
packages/nc-gui-v2/components/smartsheet-column/PercentOptions.vue

@ -11,10 +11,10 @@ if (!formState.meta?.default) formState.meta.default = null
</script>
<template>
<div class="flex flex-col mt-2">
<div class="flex flex-col mt-2 gap-2">
<div class="flex flex-row space-x-2">
<a-form-item class="flex w-1/2" label="Precision">
<a-select v-model:value="formState.meta.precision" size="small">
<a-select v-model:value="formState.meta.precision">
<a-select-option v-for="(precision, i) of precisions" :key="i" :value="precision.id">
<div class="flex flex-row items-center">
<div class="text-xs">
@ -25,7 +25,7 @@ if (!formState.meta?.default) formState.meta.default = null
</a-select>
</a-form-item>
<a-form-item label="Default Number (%)">
<a-input v-model:value="formState.meta.default" size="small" name="default" type="number" />
<a-input v-model:value="formState.meta.default" name="default" type="number" />
</a-form-item>
</div>
<div class="flex flex-row mt-2">

34
packages/nc-gui-v2/components/smartsheet-column/RatingOptions.vue

@ -64,31 +64,33 @@ watch(
</script>
<template>
<a-row>
<a-row :gutter="8">
<a-col :span="12">
<a-form-item label="Icon">
<a-select v-model:value="formState.meta.iconIdx" size="small" class="w-52">
<a-select v-model:value="formState.meta.iconIdx" class="w-52">
<a-select-option v-for="(icon, i) of iconList" :key="i" :value="i">
<component
:is="getMdiIcon(icon.full)"
class="mx-1"
:style="{
color: formState.meta.color,
}"
/>
<component
:is="getMdiIcon(icon.empty)"
:style="{
color: formState.meta.color,
}"
/>
<div class="flex items-center">
<component
:is="getMdiIcon(icon.full)"
class="mx-1"
:style="{
color: formState.meta.color,
}"
/>
<component
:is="getMdiIcon(icon.empty)"
:style="{
color: formState.meta.color,
}"
/>
</div>
</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="Max">
<a-select v-model:value="formState.meta.max" class="w-52" size="small">
<a-select v-model:value="formState.meta.max" class="w-52">
<a-select-option v-for="(v, i) in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" :key="i" :value="v">
{{ v }}
</a-select-option>

18
packages/nc-gui-v2/components/smartsheet-column/RollupOptions.vue

@ -65,15 +65,10 @@ const columns = $computed(() => {
</script>
<template>
<div class="p-4 w-full flex flex-col border-2 mb-2 mt-4">
<div class="p-6 w-full flex flex-col border-2 mb-2 mt-4">
<div class="w-full flex flex-row space-x-2">
<a-form-item class="flex w-1/2 pb-2" :label="$t('labels.childTable')" v-bind="validateInfos.fk_relation_column_id">
<a-select
v-model:value="formState.fk_relation_column_id"
size="small"
dropdown-class-name="!w-64"
@change="onDataTypeChange"
>
<a-select v-model:value="formState.fk_relation_column_id" dropdown-class-name="!w-64" @change="onDataTypeChange">
<a-select-option v-for="(table, index) in refTables" :key="index" :value="table.col.fk_column_id">
<div class="flex flex-row space-x-0.5 h-full pb-0.5 items-center justify-between">
<div class="font-semibold text-xs">{{ table.column.title }}</div>
@ -85,12 +80,7 @@ const columns = $computed(() => {
</a-select>
</a-form-item>
<a-form-item class="flex w-1/2" :label="$t('labels.childColumn')" v-bind="validateInfos.fk_rollup_column_id">
<a-select
v-model:value="formState.fk_rollup_column_id"
name="fk_rollup_column_id"
size="small"
@change="onDataTypeChange"
>
<a-select v-model:value="formState.fk_rollup_column_id" name="fk_rollup_column_id" @change="onDataTypeChange">
<a-select-option v-for="(column, index) of columns" :key="index" :value="column.id">
{{ column.title }}
</a-select-option>
@ -98,7 +88,7 @@ const columns = $computed(() => {
</a-form-item>
</div>
<a-form-item label="Aggregate function" v-bind="validateInfos.rollup_function">
<a-select v-model:value="formState.rollup_function" size="small" @change="onDataTypeChange">
<a-select v-model:value="formState.rollup_function" @change="onDataTypeChange">
<a-select-option v-for="(func, index) of aggrFunctionsList" :key="index" :value="func.value">
{{ func.text }}
</a-select-option>

2
packages/nc-gui-v2/components/smartsheet-column/SpecificDBTypeOptions.vue

@ -1,3 +1,3 @@
<template>
<SmartsheetColumnAdvancedOptions class="mt-4" />
<SmartsheetColumnAdvancedOptions class="mt-4 mb-2" />
</template>

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

@ -16,6 +16,14 @@ const column = toRef(props, 'column')
provide(ColumnInj, column)
const editColumnDropdown = ref(false)
function onVisibleChange() {
// only allow to close the EditOrAdd component
// by clicking cancel button
editColumnDropdown.value = true
}
// instantiate column update store
useProvideColumnCreateStore(meta as Ref<TableType>, column)
</script>
@ -28,8 +36,26 @@ useProvideColumnCreateStore(meta as Ref<TableType>, column)
<template v-if="!hideMenu">
<div class="flex-1" />
<SmartsheetHeaderMenu v-if="!isForm" />
<SmartsheetHeaderMenu v-if="!isForm" @edit="editColumnDropdown = true" />
</template>
<a-dropdown
v-model:visible="editColumnDropdown"
:trigger="['click']"
placement="bottomRight"
@visible-change="onVisibleChange"
>
<div />
<template #overlay>
<SmartsheetColumnEditOrAdd
class="w-full"
:edit-column-dropdown="editColumnDropdown"
@click.stop
@keydown.stop
@cancel="editColumnDropdown = false"
/>
</template>
</a-dropdown>
</div>
</template>

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

@ -12,8 +12,7 @@ import MdiDeleteIcon from '~icons/mdi/delete-outline'
import MdiMenuDownIcon from '~icons/mdi/menu-down'
const { virtual = false } = defineProps<{ virtual?: boolean }>()
const editColumnDropdown = ref(false)
const emit = defineEmits(['edit'])
const column = inject(ColumnInj)
@ -50,31 +49,14 @@ const setAsPrimaryValue = async () => {
message.error('Failed to update primary column')
}
}
function onVisibleChange() {
// only allow to close the EditOrAdd component
// by clicking cancel button
editColumnDropdown.value = true
}
</script>
<template>
<a-dropdown v-model:visible="editColumnDropdown" :trigger="['click']" @visible-change="onVisibleChange">
<span />
<template #overlay>
<SmartsheetColumnEditOrAdd
:edit-column-dropdown="editColumnDropdown"
@click.stop
@keydown.stop
@cancel="editColumnDropdown = false"
/>
</template>
</a-dropdown>
<a-dropdown :trigger="['hover']">
<a-dropdown placement="bottomRight" :trigger="['hover']">
<MdiMenuDownIcon class="text-grey nc-ui-dt-dropdown" />
<template #overlay>
<a-menu class="shadow bg-white">
<a-menu-item @click="editColumnDropdown = true">
<a-menu-item @click="emit('edit')">
<div class="nc-column-edit nc-header-menu-item">
<MdiEditIcon class="text-primary" />
<!-- Edit -->

28
packages/nc-gui-v2/components/smartsheet-header/VirtualCell.vue

@ -9,6 +9,8 @@ const props = defineProps<{ column: ColumnType & { meta: any }; hideMenu?: boole
const column = toRef(props, 'column')
const hideMenu = toRef(props, 'hideMenu')
const editColumnDropdown = ref(false)
provide(ColumnInj, column)
const { metas } = useMetas()
@ -76,6 +78,12 @@ const tooltipMsg = computed(() => {
return ''
})
function onVisibleChange() {
// only allow to close the EditOrAdd component
// by clicking cancel button
editColumnDropdown.value = true
}
useProvideColumnCreateStore(meta as Ref<TableType>, column)
</script>
@ -101,8 +109,26 @@ useProvideColumnCreateStore(meta as Ref<TableType>, column)
<template v-if="!hideMenu">
<v-spacer />
<SmartsheetHeaderMenu v-if="!isForm" :virtual="true" />
<SmartsheetHeaderMenu v-if="!isForm" :virtual="true" @edit="editColumnDropdown = true" />
</template>
<a-dropdown
v-model:visible="editColumnDropdown"
:trigger="['click']"
placement="bottomRight"
@visible-change="onVisibleChange"
>
<div />
<template #overlay>
<SmartsheetColumnEditOrAdd
class="w-full"
:edit-column-dropdown="editColumnDropdown"
@click.stop
@keydown.stop
@cancel="editColumnDropdown = false"
/>
</template>
</a-dropdown>
</div>
</template>

8
packages/nc-gui-v2/components/smartsheet/Grid.vue

@ -482,10 +482,10 @@ const expandForm = (row: Row, state: Record<string, any>) => {
table,
td,
th {
border-right: 1px solid #7f828b33 !important;
border-left: 1px solid #7f828b33 !important;
border-bottom: 1px solid #7f828b33 !important;
border-top: 1px solid #7f828b33 !important;
border-right: 1px solid #f0f0f0 !important;
border-left: 1px solid #f0f0f0 !important;
border-bottom: 1px solid #f0f0f0 !important;
border-top: 1px solid #f0f0f0 !important;
border-collapse: collapse;
}

6
packages/nc-gui-v2/components/smartsheet/Toolbar.vue

@ -5,7 +5,7 @@ const { isGrid, isForm } = useSmartsheetStoreOrThrow()
</script>
<template>
<div class="nc-table-toolbar w-full py-1 flex gap-1 items-center h-[48px] px-2" style="z-index: 7">
<div class="nc-table-toolbar w-full py-1 flex gap-1 items-center h-[48px] px-2 border-b" style="z-index: 7">
<SmartsheetToolbarFieldsMenu v-if="isGrid" :show-system-fields="false" class="ml-1" />
<SmartsheetToolbarColumnFilterMenu v-if="isGrid" />
@ -26,4 +26,8 @@ const { isGrid, isForm } = useSmartsheetStoreOrThrow()
:deep(.nc-toolbar-btn) {
@apply border-0 !text-xs font-semibold px-2;
}
.nc-table-toolbar {
border-color: #f0f0f0 !important;
}
</style>

46
packages/nc-gui-v2/components/tabs/Auth.vue

@ -2,42 +2,48 @@
import UserManagement from './auth/UserManagement.vue'
import ApiTokenManagement from './auth/ApiTokenManagement.vue'
interface TabGroup {
[key: string]: {
title: string
body: any
}
interface Tab {
title: string
body: any
}
const tabsInfo: TabGroup = {
usersManagement: {
const tabsInfo: Tab[] = [
{
title: 'Users Management',
body: () => UserManagement,
},
apiTokenManagement: {
{
title: 'API Token Management',
body: () => ApiTokenManagement,
},
}
]
const firstKeyOfObject = (obj: object) => Object.keys(obj)[0]
// const firstKeyOfObject = (obj: object) => Object.keys(obj)[0]
const selectedTabKeys = $ref<string[]>([firstKeyOfObject(tabsInfo)])
const selectedTab = $computed(() => tabsInfo[selectedTabKeys[0]])
const selectedTabKey = $ref(0)
const selectedTab = $computed(() => tabsInfo[selectedTabKey])
</script>
<template>
<div class="mt-2">
<a-menu v-model:selectedKeys="selectedTabKeys" :open-keys="[]" mode="horizontal">
<a-menu-item v-for="(tab, key) of tabsInfo" :key="key" class="select-none">
<div class="text-xs pb-2.5">
{{ tab.title }}
</div>
</a-menu-item>
</a-menu>
<div>
<a-tabs v-model:active-key="selectedTabKey" :open-keys="[]" mode="horizontal" class="nc-auth-tabs mx-6">
<a-tabs-tab-pane v-for="(tab, key) of tabsInfo" :key="key" class="select-none">
<template #tab>
<span>
{{ tab.title }}
</span>
</template>
</a-tabs-tab-pane>
</a-tabs>
<div class="mx-4 py-6 mt-2">
<component :is="selectedTab.body()" />
</div>
</div>
</template>
<style scoped>
:deep(.nc-auth-tabs .ant-tabs-nav::before) {
@apply !border-none;
}
</style>

2
packages/nc-gui-v2/components/tabs/auth/ApiTokenManagement.vue

@ -124,7 +124,7 @@ onMounted(() => {
<div class="text-gray-500">Reload</div>
</div>
</a-button>
<a-button size="middle" @click="openNewTokenModal">
<a-button size="middle" type="primary" ghost @click="openNewTokenModal">
<div class="flex flex-row justify-center items-center caption capitalize space-x-1">
<MdiPlusIcon />
<div>Add New Token</div>

2
packages/nc-gui-v2/components/tabs/auth/UserManagement.vue

@ -178,7 +178,7 @@ watchDebounced(searchText, () => loadUsers(), { debounce: 300, maxWait: 600 })
<div class="text-gray-500">Reload</div>
</div>
</a-button>
<a-button v-if="isUIAllowed('newUser')" size="middle" @click="onInvite">
<a-button v-if="isUIAllowed('newUser')" size="middle" type="primary" ghost @click="onInvite">
<div class="flex flex-row justify-center items-center caption capitalize space-x-1">
<MidAccountIcon />
<div>{{ $t('activity.inviteTeam') }}</div>

2
packages/nc-gui-v2/layouts/base.vue

@ -19,7 +19,7 @@ const logout = () => {
<div id="nc-sidebar-left" />
<a-layout class="!flex-col">
<a-layout-header class="flex !bg-primary items-center text-white pl-1 pr-4 shadow-lg">
<a-layout-header class="flex !bg-primary items-center text-white pl-4 pr-5 shadow-lg">
<div
v-if="route.name === 'index' || route.name === 'project-index-create' || route.name === 'project-index-create-external'"
class="transition-all duration-200 p-2 cursor-pointer transform hover:scale-105"

4
packages/nc-gui-v2/pages/nc/[projectId]/index.vue

@ -56,7 +56,7 @@ await loadTables()
collapsible
theme="light"
>
<div style="height: var(--header-height)" class="flex items-center !bg-primary text-white px-1 gap-2">
<div style="height: var(--header-height)" class="flex items-center !bg-primary text-white px-1 pl-5 gap-2">
<div
v-if="isOpen"
class="w-[40px] min-w-[40px] transition-all duration-200 p-1 cursor-pointer transform hover:scale-105"
@ -65,7 +65,7 @@ await loadTables()
<img alt="NocoDB" src="~/assets/img/icons/512x512-trans.png" />
</div>
<a-dropdown v-model:visible="dropdownOpen" :trigger="['click']">
<a-dropdown v-model:visible="dropdownOpen" :trigger="['click']" placement="bottom">
<div
:style="{ width: isOpen ? 'calc(100% - 40px) pr-2' : '100%' }"
:class="[isOpen ? '' : 'justify-center']"

35
packages/nc-gui-v2/pages/nc/[projectId]/index/index.vue

@ -46,7 +46,7 @@ const icon = (tab: TabItem) => {
<div class="h-full w-full nc-container pt-[9px]">
<div class="h-full w-full flex flex-col">
<div>
<a-tabs v-model:activeKey="activeTabIndex" type="editable-card" @edit="closeTab">
<a-tabs v-model:activeKey="activeTabIndex" class="nc-root-tabs" type="editable-card" @edit="closeTab">
<a-tab-pane v-for="(tab, i) in tabs" :key="i">
<template #tab>
<div class="flex align-center gap-2">
@ -154,14 +154,29 @@ const icon = (tab: TabItem) => {
</div>
</template>
<style scoped>
<style scoped lang="scss">
.nc-container {
height: calc(100% - var(--header-height));
flex: 1 1 100%;
}
:deep(.ant-tabs-nav) {
@apply !mb-0;
:deep(.nc-root-tabs) {
& > .ant-tabs-nav {
@apply !mb-0;
& > .ant-tabs-nav-wrap > .ant-tabs-nav-list {
& > .ant-tabs-nav-add {
@apply !hidden;
}
& > .ant-tabs-tab-active {
@apply font-weight-medium;
}
& > .ant-tabs-tab:not(.ant-tabs-tab-active) {
@apply bg-gray-100;
}
}
}
}
:deep(.ant-menu-item-selected) {
@ -173,16 +188,4 @@ const icon = (tab: TabItem) => {
:deep(.ant-menu-submenu::after) {
@apply !border-none;
}
:deep(.ant-tabs-nav-add) {
@apply !hidden;
}
:deep(.ant-tabs-tab-active) {
@apply font-weight-medium;
}
:deep(.ant-tabs-tab:not(.ant-tabs-tab-active)) {
@apply bg-gray-100;
}
</style>

Loading…
Cancel
Save