Browse Source

feat(gui-v2): view create

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/2716/head
Pranav C 2 years ago
parent
commit
b46608f5f8
  1. 116
      packages/nc-gui-v2/components/dlg/ViewCreate.vue
  2. 97
      packages/nc-gui-v2/components/dlg/VueCreate.vue
  3. 7
      packages/nc-gui-v2/components/index.ts
  4. 20
      packages/nc-gui-v2/components/smartsheet/Sidebar.vue
  5. 71
      packages/nc-gui-v2/composables/useViewCreate.ts

116
packages/nc-gui-v2/components/dlg/ViewCreate.vue

@ -0,0 +1,116 @@
<script setup lang="ts">
import { inject } from '@vue/runtime-core'
import type { TableType, ViewTypes } from 'nocodb-sdk'
import type { Ref } from '#imports'
import { MetaInj, ViewListInj } from '~/components'
import useViewCreate from '~/composables/useViewCreate'
const { modelValue, type, selectedViewId } = defineProps<{ type: ViewTypes; modelValue: boolean; selectedViewId?:string }>()
const emit = defineEmits(['update:modelValue', 'created'])
const valid =ref(false)
const viewList = inject(ViewListInj)
const dialogShow = computed({
get() {
return modelValue
},
set(v) {
emit('update:modelValue', v)
},
})
const { view, createView, generateUniqueTitle, loading } = useViewCreate(inject(MetaInj) as Ref<TableType>, (view) => emit('created', view))
/* name: 'CreateViewDialog',
props: [
'value',
'nodes',
'table',
'alias',
'show_as',
'viewsCount',
'primaryValueColumn',
'meta',
'copyView',
'viewsList',
'selectedViewId',
],
data: () => ({
valid: false,
view_name: '',
loading: false,
queryParams: {},
}),
computed: {
localState: {
get() {
return this.value;
},
set(v) {
this.$emit('input', v);
},
},
typeAlias() {
return {
[ViewTypes.GRID]: 'grid',
[ViewTypes.GALLERY]: 'gallery',
[ViewTypes.FORM]: 'form',
[ViewTypes.KANBAN]: 'kanban',
}[this.show_as];
},
},
mounted() {
try {
if (this.copyView && this.copyView.query_params) {
this.queryParams = { ...JSON.parse(this.copyView.query_params) };
}
} catch (e) {}
this.view_name = `${this.alias || this.table}${this.viewsCount}`;
this.$nextTick(() => {
const input = this.$refs.name.$el.querySelector('input');
input.setSelectionRange(0, this.view_name.length);
input.focus();
});
}, */
</script>
<template>
<v-dialog v-model="dialogShow" max-width="600" min-width="400">
<v-card class="elevation-20">
<v-card-title class="grey darken-2 subheading" style="height: 30px" />
<v-card-text class="pt-4 pl-4">
<p class="headline">
{{ $t('general.create') }} <span class="text-capitalize">{{ type }}</span> {{ $t('objects.view') }}
</p>
<v-form ref="form" v-model="valid" @submit.prevent="createView">
<!-- label="View Name" -->
<v-text-field
ref="name"
v-model="view.title"
:label="$t('labels.viewName')"
:rules="[
(v) => !!v || 'View name required',
(v) => (viewList || []).every((v1) => (v1.alias || v1.title) !== v) || 'View name should be unique',
]"
autofocus
/>
</v-form>
</v-card-text>
<v-card-actions class="pa-4">
<v-spacer />
<v-btn class="" small @click="emit('update:modelValue', false)">
{{ $t('general.cancel') }}
</v-btn>
<v-btn small :loading="loading" class="primary" :disabled="!valid" @click="createView(type, selectedViewId)">
{{ $t('general.submit') }}
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<style scoped></style>

97
packages/nc-gui-v2/components/dlg/VueCreate.vue

@ -1,97 +0,0 @@
<script setup lang="ts">
import { ViewTypes } from "nocodb-sdk";
import useViewCreate from "~/composables/useViewCreate";
const { modelValue, type } = defineProps<{ type: ViewTypes, modelValue: boolean }>();
const emit = defineEmits(["update:modelValue"]);
const dialogShow = computed({
get() {
return modelValue;
},
set(v) {
emit("update:modelValue", v);
}
});
const { view, createView, generateUniqueTitle } = useViewCreate(async () => {
});
/*import inflection from 'inflection'
export default {
name: 'DlgViewCreate',
props: ['value'],
data() {
return {
view: {
name: '',
},
}
},
computed: {
dialogShow: {
get() {
return this.value
},
set(v) {
this.$emit('input', v)
},
},
projectPrefix() {
return this.$store.getters['project/GtrProjectPrefix']
},
},
watch: {
'view.alias': function (v) {
this.$set(this.view, 'name', `${this.projectPrefix || ''}${inflection.underscore(v)}`)
},
},
mounted() {
setTimeout(() => {
this.$refs.input.$el.querySelector('input').focus()
}, 100)
},
}*/
</script>
<template>
<v-dialog v-model="dialogShow" max-width="500">
<v-card class="elevation-20">
<v-card-title class="grey darken-2 subheading" style="height: 30px" />
<v-card-text class="pt-4 pl-4">
<p class="headline">
{{ $t('general.create') }} <span class="text-capitalize">{{ typeAlias }}</span> {{ $t('objects.view') }}
</p>
<v-form ref="form" v-model="valid" @submit.prevent="createView">
<!-- label="View Name" -->
<v-text-field
ref="name"
v-model="view.title"
:label="$t('labels.viewName')"
:rules="[
v => !!v || 'View name required',
v => viewsList.every(v1 => (v1.alias || v1.title) !== v) || 'View name should be unique',
]"
autofocus
/>
</v-form>
</v-card-text>
<v-card-actions class="pa-4">
<v-spacer />
<v-btn class="" small @click="$emit('input', false)">
{{ $t('general.cancel') }}
</v-btn>
<v-btn small :loading="loading" class="primary" :disabled="!valid" @click="createView">
{{ $t('general.submit') }}
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<style scoped></style>

7
packages/nc-gui-v2/components/index.ts

@ -3,6 +3,8 @@ import type { InjectionKey, Ref } from 'vue'
import type { EventHook } from '@vueuse/core'
import type useViewData from '~/composables/useViewData'
export type ViewType = (GridType | GalleryType | FormType | KanbanType) & { id?: string }
export const ColumnInj: InjectionKey<ColumnType & { meta: any }> = Symbol('column-injection')
export const MetaInj: InjectionKey<Ref<TableType>> = Symbol('meta-injection')
export const TabMetaInj: InjectionKey<any> = Symbol('tab-meta-injection')
@ -13,9 +15,8 @@ export const IsFormInj: InjectionKey<boolean> = Symbol('is-form-injection')
export const IsGridInj: InjectionKey<boolean> = Symbol('is-grid-injection')
export const IsLockedInj: InjectionKey<boolean> = Symbol('is-locked-injection')
export const ValueInj: InjectionKey<any> = Symbol('value-injection')
export const ActiveViewInj: InjectionKey<Ref<(GridType | GalleryType | FormType | KanbanType) & { id?: string }>> =
Symbol('active-view-injection')
export const ActiveViewInj: InjectionKey<Ref<ViewType>> = Symbol('active-view-injection')
export const ReadonlyInj: InjectionKey<any> = Symbol('readonly-injection')
export const ReloadViewDataHookInj: InjectionKey<EventHook<void>> = Symbol('reload-view-data-injection')
export const FieldsInj: InjectionKey<Ref<any[]>> = Symbol('fields-injection')
export const ViewListInj: InjectionKey<Ref<any[]>> = Symbol('view-list-injection')
export const ViewListInj: InjectionKey<Ref<ViewType[]>> = Symbol('view-list-injection')

20
packages/nc-gui-v2/components/smartsheet/Sidebar.vue

@ -3,7 +3,7 @@ import { ViewTypes } from 'nocodb-sdk'
import type { TableType } from 'nocodb-sdk'
import type { Ref } from 'vue'
import { inject, ref } from '#imports'
import { ActiveViewInj, MetaInj } from '~/components'
import { ActiveViewInj, MetaInj, ViewListInj } from '~/components'
import useViews from '~/composables/useViews'
import { viewIcons } from '~/utils/viewUtils'
import MdiPlusIcon from '~icons/mdi/plus'
@ -17,6 +17,7 @@ provide(ViewListInj, views)
const _isUIAllowed = (view: string) => {}
// todo decide based on route param
loadViews().then(() => {
activeView.value = views.value?.[0]
})
@ -25,12 +26,19 @@ const toggleDrawer = ref(false)
// todo: identify based on meta
const isView = ref(false)
const viewCreateType = ref<ViewTypes>()
const viewCreateDlg = ref<boolean>()
const viewCreateDlg = ref<boolean>(false)
const openCreateViewDlg = (type: ViewTypes) => {
viewCreateDlg.value = true
viewCreateType.value = type
}
const onViewCreate = (view)=>{
views.value?.push(view)
activeView.value = view
viewCreateDlg.value = false
}
</script>
<template>
@ -188,7 +196,7 @@ const openCreateViewDlg = (type: ViewTypes) => {
</v-list-item>
<v-tooltip bottom>
<template #activator="{ on }">
<v-list-item dense class="body-2 nc-create-grid-view" v-on="on" @click="openCreateViewDlg(viewTypes.GRID)">
<v-list-item dense class="body-2 nc-create-grid-view" v-on="on" @click="openCreateViewDlg(ViewTypes.GRID)">
<!-- <v-list-item-icon class="mr-n1"> -->
<component :is="viewIcons[ViewTypes.GRID].icon" :class="`text-${viewIcons[ViewTypes.GRID].color} mr-1`" />
<!-- </v-list-item-icon> -->
@ -208,7 +216,7 @@ const openCreateViewDlg = (type: ViewTypes) => {
</v-tooltip>
<v-tooltip bottom>
<template #activator="{ on }">
<v-list-item dense class="body-2 nc-create-gallery-view" v-on="on" @click="openCreateViewDlg(viewTypes.GALLERY)">
<v-list-item dense class="body-2 nc-create-gallery-view" v-on="on" @click="openCreateViewDlg(ViewTypes.GALLERY)">
<!-- <v-list-item-icon class="mr-n1"> -->
<component :is="viewIcons[ViewTypes.GALLERY].icon" :class="`text-${viewIcons[ViewTypes.GALLERY].color} mr-1`" />
<!-- </v-list-item-icon> -->
@ -236,7 +244,7 @@ const openCreateViewDlg = (type: ViewTypes) => {
dense
class="body-2 nc-create-form-view"
v-on="on"
@click="openCreateViewDlg(viewTypes.FORM)"
@click="openCreateViewDlg(ViewTypes.FORM)"
>
<!-- <v-list-item-icon class="mr-n1"> -->
<component :is="viewIcons[ViewTypes.FORM].icon" :class="`text-${viewIcons[ViewTypes.FORM].color} mr-1`" />
@ -262,7 +270,7 @@ const openCreateViewDlg = (type: ViewTypes) => {
</div>
</div>
<DlgViewCreate v-model="viewCreateDlg" :type="viewCreateType" />
<DlgViewCreate v-model="viewCreateDlg" :type="viewCreateType" @created="onViewCreate"/>
</div>
</template>

71
packages/nc-gui-v2/composables/useViewCreate.ts

@ -1,32 +1,63 @@
import type { ViewTypes } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk'
import type { TableType } from 'nocodb-sdk'
import { ViewTypes } from 'nocodb-sdk'
import type { Ref } from 'vue'
import { useToast } from 'vue-toastification'
import { useNuxtApp } from '#app'
import useMetas from '~/composables/useMetas'
export default (onViewCreate?: (viewMeta: any) => void) => {
export default (meta: Ref<TableType>, onViewCreate?: (viewMeta: any) => void) => {
const view = reactive<{ title: string; type?: ViewTypes }>({
title: '',
})
const loading = ref(false)
const { $api } = useNuxtApp()
const toast = useToast()
const { metas } = useMetas()
const createView = async () => {
if (!sqlUi?.value) return
const columns = sqlUi?.value?.getNewTableColumns().filter((col) => {
if (col.column_name === 'id' && table.columns.includes('id_ag')) {
Object.assign(col, sqlUi?.value?.getDataTypeForUiType({ uidt: UITypes.ID }, 'AG'))
col.dtxp = sqlUi?.value?.getDefaultLengthForDatatype(col.dt)
col.dtxs = sqlUi?.value?.getDefaultScaleForDatatype(col.dt)
return true
}
return table.columns.includes(col.column_name)
})
const createView = async (viewType: ViewTypes, selectedViewId = null) => {
loading.value = true
const tableMeta = await $api.dbTable.create(project?.value?.id as string, {
...table,
columns,
})
try {
let data
switch (viewType) {
case ViewTypes.GRID:
// todo: update swagger
data = await $api.dbView.gridCreate(
meta?.value?.id as string,
{
title: view?.title,
copy_from_id: selectedViewId,
} as any,
)
break
case ViewTypes.GALLERY:
data = await $api.dbView.galleryCreate(
meta?.value?.id as string,
{
title: view?.title,
copy_from_id: selectedViewId,
} as any,
)
break
case ViewTypes.FORM:
data = await $api.dbView.formCreate(
meta?.value?.id as string,
{
title: view?.title,
copy_from_id: selectedViewId,
} as any,
)
break
}
toast.success('View created successfully')
onViewCreate?.(data)
} catch (e) {
toast.error(e.message)
}
onViewCreate?.(tableMeta)
loading.value = false
}
const generateUniqueTitle = () => {
@ -37,5 +68,5 @@ export default (onViewCreate?: (viewMeta: any) => void) => {
// table.title = `Sheet${c}`
}
return { view, createView, generateUniqueTitle }
return { view, createView, generateUniqueTitle, loading }
}

Loading…
Cancel
Save