Browse Source

feat(gui-v2): update tab state on table rename

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2830/head
Pranav C 2 years ago
parent
commit
b7ce972695
  1. 21
      packages/nc-gui-v2/components/dashboard/TreeView.vue
  2. 105
      packages/nc-gui-v2/components/dlg/TableRename.vue
  3. 21
      packages/nc-gui-v2/composables/useTabs.ts
  4. 2
      packages/nc-gui-v2/pages/nc/[projectId].vue

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

@ -113,7 +113,7 @@ const setMenuContext = (type: 'table' | 'main', value?: any) => {
}
const deleteTable = (table: TableType) => {
$e('c:table:delete');
$e('c:table:delete')
// 'Click Submit to Delete The table'
Modal.confirm({
title: `Click Yes to Delete The table : ${table.title}`,
@ -195,7 +195,7 @@ const showRenameTableDlg = (table: TableType) => {
<span class="flex-grow text-bold"
>{{ $t('objects.tables') }} <template v-if="tables?.length">({{ tables.length }})</template></span
>
<MdiPlus class="text-gray-500" @click.stop="tableCreateDlg = true" v-t="['c:table:create:navdraw']"/>
<MdiPlus v-t="['c:table:create:navdraw']" class="text-gray-500" @click.stop="tableCreateDlg = true" />
<MdiMenuDown
class="transition-transform !duration-100 text-gray-500"
:class="{ 'transform rotate-180': showTableList }"
@ -207,11 +207,11 @@ const showRenameTableDlg = (table: TableType) => {
<a-menu-item
v-for="table in filteredTables"
:key="table.id"
v-t="['a:table:open']"
class="!pl-1 py-1 !h-[28px] !my-0 text-sm pointer group"
:data-order="table.order"
:data-id="table.id"
@click="addTab({ type: 'table', title: table.title, id: table.id })"
v-t="['a:table:open']"
>
<div class="flex align-center gap-1 h-full" @contextmenu="setMenuContext('table', table)">
<MdiDrag class="transition-opacity opacity-0 group-hover:opacity-100 text-gray-500 nc-drag-icon cursor-move" />
@ -222,8 +222,9 @@ const showRenameTableDlg = (table: TableType) => {
<MdiMenuIcon class="transition-opacity opacity-0 group-hover:opacity-100" />
<template #overlay>
<a-menu class="cursor-pointer">
<a-menu-item class="!text-xs"
v-t="['c:table:rename:navdraw:options']" @click="showRenameTableDlg(table)"> Rename</a-menu-item>
<a-menu-item v-t="['c:table:rename:navdraw:options']" class="!text-xs" @click="showRenameTableDlg(table)">
Rename</a-menu-item
>
<a-menu-item class="!text-xs" @click="deleteTable(table)"> Delete</a-menu-item>
</a-menu>
</template>
@ -238,12 +239,16 @@ const showRenameTableDlg = (table: TableType) => {
<template #overlay>
<a-menu class="cursor-pointer">
<template v-if="contextMenuTarget.type === 'table'">
<a-menu-item class="!text-xs"
v-t="['c:table:rename:navdraw:right-click']" @click="showRenameTableDlg(contextMenuTarget.value)">Table Rename</a-menu-item>
<a-menu-item
v-t="['c:table:rename:navdraw:right-click']"
class="!text-xs"
@click="showRenameTableDlg(contextMenuTarget.value)"
>Table Rename</a-menu-item
>
<a-menu-item class="!text-xs" @click="deleteTable(contextMenuTarget.value)">Table Delete</a-menu-item>
</template>
<template v-else>
<a-menu-item class="!text-xs" @click="loadTables" v-t="['a:table:refresh:navdraw']">Tables Refresh</a-menu-item>
<a-menu-item v-t="['a:table:refresh:navdraw']" class="!text-xs" @click="loadTables">Tables Refresh</a-menu-item>
</template>
</a-menu>
</template>

105
packages/nc-gui-v2/components/dlg/TableRename.vue

@ -1,90 +1,89 @@
<script setup lang="ts">
import { onMounted, watchEffect } from "@vue/runtime-core";
import { Form } from "ant-design-vue";
import type { TableType } from "nocodb-sdk";
import { useToast } from "vue-toastification";
import { useProject, useTableCreate, useTabs } from "#imports";
import { extractSdkResponseErrorMsg } from "~/utils/errorUtils";
import { validateTableName } from "~/utils/validation";
import { useNuxtApp } from "#app";
import { onMounted, watchEffect } from '@vue/runtime-core'
import { Form } from 'ant-design-vue'
import type { TableType } from 'nocodb-sdk'
import { useToast } from 'vue-toastification'
import { useProject, useTableCreate, useTabs } from '#imports'
import { extractSdkResponseErrorMsg } from '~/utils/errorUtils'
import { validateTableName } from '~/utils/validation'
import { useNuxtApp } from '#app'
interface Props {
modelValue?: boolean;
tableMeta: TableType;
modelValue?: boolean
tableMeta: TableType
}
const { modelValue = false, tableMeta } = defineProps<Props>();
const emit = defineEmits(["update:modelValue", "updated"]);
const { $e, $api } = useNuxtApp();
const toast = useToast();
const { modelValue = false, tableMeta } = defineProps<Props>()
const emit = defineEmits(['update:modelValue', 'updated'])
const { $e, $api } = useNuxtApp()
const toast = useToast()
const dialogShow = computed({
get() {
return modelValue;
return modelValue
},
set(v) {
emit("update:modelValue", v);
}
});
emit('update:modelValue', v)
},
})
const { addTab } = useTabs();
const { loadTables } = useProject();
const { project, tables } = useProject();
const { updateTab } = useTabs()
const { loadTables } = useProject()
const { project, tables } = useProject()
const prefix = computed(() => project?.value?.prefix || "");
const prefix = computed(() => project?.value?.prefix || '')
const validateDuplicateAlias = (v: string) => {
return (tables?.value || []).every((t) => t.title !== (v || "")) || "Duplicate table alias";
};
return (tables?.value || []).every((t) => t.title !== (v || '')) || 'Duplicate table alias'
}
const validateLeadingOrTrailingWhiteSpace = (v: string) => {
return !/^\s+|\s+$/.test(v) || "Leading or trailing whitespace not allowed in table name";
};
return !/^\s+|\s+$/.test(v) || 'Leading or trailing whitespace not allowed in table name'
}
const validateDuplicate = (v: string) => {
return (tables?.value || []).every((t) => t.table_name.toLowerCase() !== (v || "").toLowerCase()) || "Duplicate table name";
};
const inputEl = $ref<any>();
const useForm = Form.useForm;
return (tables?.value || []).every((t) => t.table_name.toLowerCase() !== (v || '').toLowerCase()) || 'Duplicate table name'
}
const inputEl = $ref<any>()
const useForm = Form.useForm
const formState = reactive({
title: ""
});
title: '',
})
const validators = computed(() => {
return {
title: [validateTableName, validateDuplicateAlias],
table_name: [validateTableName]
};
});
const { resetFields, validate, validateInfos } = useForm(formState, validators);
table_name: [validateTableName],
}
})
const { resetFields, validate, validateInfos } = useForm(formState, validators)
watchEffect(() => {
if (tableMeta?.title) formState.title = tableMeta?.title;
if (tableMeta?.title) formState.title = tableMeta?.title
// todo: replace setTimeout and follow better approach
nextTick(() => {
const input = inputEl?.$el;
input.setSelectionRange(0, formState.title.length);
input.focus();
});
});
const input = inputEl?.$el
input.setSelectionRange(0, formState.title.length)
input.focus()
})
})
const renameTable = async () => {
try {
await $api.dbTable.update(tableMeta?.id as string, {
title: formState.title
});
title: formState.title,
})
loadTables();
toast.success("Table renamed successfully");
$e("a:table:rename");
loadTables()
updateTab({ id: tableMeta?.id }, { title: formState.title })
toast.success('Table renamed successfully')
$e('a:table:rename')
} catch (e) {
toast.error(await extractSdkResponseErrorMsg(e));
toast.error(await extractSdkResponseErrorMsg(e))
}
};
}
</script>
<template>
<a-modal v-model:visible="dialogShow" @keydown.esc="dialogShow = false" @finish="renameTable">
<template #footer>
<a-button key="back" @click="dialogShow = false">{{ $t("general.cancel") }}</a-button>
<a-button key="submit" type="primary" @click="renameTable">{{ $t("general.submit") }}</a-button>
<a-button key="back" @click="dialogShow = false">{{ $t('general.cancel') }}</a-button>
<a-button key="submit" type="primary" @click="renameTable">{{ $t('general.submit') }}</a-button>
</template>
<div class="pl-10 pr-10 pt-5">
<a-form :model="formState" name="create-new-table-form">

21
packages/nc-gui-v2/composables/useTabs.ts

@ -6,6 +6,13 @@ export interface TabItem {
id?: string
}
function getPredicate(key: Partial<TabItem>) {
return (tab: TabItem) =>
(!('id' in key) || tab.id === key.id) &&
(!('title' in key) || tab.title === key.id) &&
(!('type' in key) || tab.type === key.id)
}
export default () => {
const tabs = useState<TabItem[]>('tabs', () => [])
const activeTab = useState<number>('activeTab', () => 0)
@ -25,13 +32,21 @@ export default () => {
const clearTabs = () => {
tabs.value = []
}
const closeTab = (key: number | TabItem) => {
const closeTab = (key: number | Partial<TabItem>) => {
if (typeof key === 'number') tabs.value.splice(key, 1)
else {
const index = tabs.value.findIndex((tab) => tab.id === key.id && tab.type === key.type && tab.title === key.title)
const index = tabs.value.findIndex(getPredicate(key))
if (index > -1) tabs.value.splice(index, 1)
}
}
return { tabs, addTab, activeTab, clearTabs, closeTab }
const updateTab = (key: number | Partial<TabItem>, newTabItemProps: Partial<TabItem>) => {
const tab = typeof key === 'number' ? tabs.value[key] : tabs.value.find(getPredicate(key))
if (tab) {
Object.assign(tab, newTabItemProps)
}
}
return { tabs, addTab, activeTab, clearTabs, closeTab, updateTab }
}

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

@ -2,7 +2,7 @@
const route = useRoute()
const { loadProject, loadTables } = useProject(route.params.projectId as string)
const { clearTabs, addTab } = useTabs()
const {$state} = useNuxtApp()
const { $state } = useNuxtApp()
addTab({ type: 'auth', title: 'Team & Auth' })

Loading…
Cancel
Save