Browse Source

refactor(gui-v2): add view menu and move items

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/3262/head
Pranav C 2 years ago
parent
commit
f242588992
  1. 359
      packages/nc-gui-v2/components/smartsheet-toolbar/ViewActions.vue
  2. 24
      packages/nc-gui-v2/components/smartsheet/Toolbar.vue
  3. 37
      packages/nc-gui-v2/components/smartsheet/sidebar/MenuBottom.vue
  4. 2
      packages/nc-gui-v2/components/smartsheet/sidebar/MenuTop.vue
  5. 16
      packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/index.vue
  6. 9
      packages/nc-gui-v2/components/tabs/Smartsheet.vue

359
packages/nc-gui-v2/components/smartsheet-toolbar/ViewActions.vue

@ -0,0 +1,359 @@
<script lang="ts" setup>
import * as XLSX from 'xlsx'
import { ExportTypes } from 'nocodb-sdk'
import FileSaver from 'file-saver'
import { message } from 'ant-design-vue'
import { viewIcons } from '~/utils'
import {
ActiveViewInj,
FieldsInj,
IsLockedInj,
IsPublicInj,
MetaInj,
extractSdkResponseErrorMsg,
inject,
ref,
useNuxtApp,
useProject,
useUIPermission,
} from '#imports'
import MdiLockOutlineIcon from '~icons/mdi/lock-outline'
import MdiAccountIcon from '~icons/mdi/account'
import MdiAccountGroupIcon from '~icons/mdi/account-group'
enum LockType {
Personal = 'personal',
Locked = 'locked',
Collaborative = 'collaborative',
}
const sharedViewListDlg = ref(false)
const isPublicView = inject(IsPublicInj, ref(false))
const isView = false
const { project } = useProject()
const { $api } = useNuxtApp()
const meta = inject(MetaInj)
const fields = inject(FieldsInj, ref([]))
const selectedView = inject(ActiveViewInj)
const isLocked = inject(IsLockedInj)
const showWebhookDrawer = ref(false)
const quickImportDialog = ref(false)
const { isUIAllowed } = useUIPermission()
const exportFile = async (exportType: ExportTypes) => {
let offset = 0
let c = 1
const responseType = exportType === ExportTypes.EXCEL ? 'base64' : 'blob'
try {
while (!isNaN(offset) && offset > -1) {
let res
if (isPublicView.value) {
const { exportFile: sharedViewExportFile } = useSharedView()
res = await sharedViewExportFile(fields.value, offset, exportType, responseType)
} else {
res = await $api.dbViewRow.export(
'noco',
project?.value.title as string,
meta?.value.title as string,
selectedView?.value.title as string,
exportType,
{
responseType,
query: {
offset,
},
} as any,
)
}
const { data, headers } = res
if (exportType === ExportTypes.EXCEL) {
const workbook = XLSX.read(data, { type: 'base64' })
XLSX.writeFile(workbook, `${meta?.value.title}_exported_${c++}.xlsx`)
} else if (exportType === ExportTypes.CSV) {
const blob = new Blob([data], { type: 'text/plain;charset=utf-8' })
FileSaver.saveAs(blob, `${meta?.value.title}_exported_${c++}.csv`)
}
offset = +headers['nc-export-offset']
if (offset > -1) {
message.info('Downloading more files')
} else {
message.success('Successfully exported all table data')
}
}
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
}
const Icon = computed(() => {
switch ((selectedView?.value as any)?.lock_type) {
case LockType.Personal:
return MdiAccountIcon
case LockType.Locked:
return MdiLockOutlineIcon
case LockType.Collaborative:
default:
return MdiAccountGroupIcon
}
})
async function changeLockType(type: LockType) {
$e('a:grid:lockmenu', { lockType: type })
if (type === 'personal') {
return message.info('Coming soon')
}
try {
;(view.value as any).lock_type = type
$api.dbView.update(view.value.id as string, {
lock_type: type,
})
message.success(`Successfully Switched to ${type} view`)
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
}
</script>
<template>
<div>
<a-dropdown>
<a-button v-t="['c:actions']" class="nc-actions-menu-btn nc-toolbar-btn">
<div class="flex gap-2 align-center">
<component
:is="viewIcons[selectedView?.type].icon"
class="nc-view-icon group-hover:hidden"
:class="`text-${viewIcons[selectedView?.type].color}`"
/>
<span class="!text-sm font-weight-medium">{{ selectedView?.title }}</span>
<component :is="Icon" />
<MdiMenuDown class="text-grey" />
</div>
</a-button>
<template #overlay>
<a-menu class="ml-6 !text-sm !p-0 !rounded">
<a-menu-item-group>
<a-sub-menu key="lock-type" v-if="isUIAllowed('view-type')" >
<template #title>
<div v-t="['c:navdraw:preview-as']" class="nc-project-menu-item group">
<MdiFileEyeOutline class="group-hover:text-pink-500" />
Lock Type
<div class="flex-1" />
<MaterialSymbolsChevronRightRounded
class="transform group-hover:(scale-115 text-pink-500) text-xl text-gray-400"
/>
</div>
</template>
<template #expandIcon></template>
<a-menu-item>
<!-- <div class="min-w-[350px] max-w-[500px] shadow bg-white"> -->
<!-- <div> -->
<div class="nc-menu-item" @click="changeLockType(LockType.Collaborative)">
<div>
<MdiCheck v-if="!view?.lock_type || view?.lock_type === LockType.Collaborative" />
<span v-else />
<div>
<MdiAccountGroupIcon />
Collaborative view
<div class="nc-subtitle">
Collaborators with edit permissions or higher can change the view configuration.
</div>
</div>
</div>
</div>
</a-menu-item>
<a-menu-item>
<div class="nc-menu-item" @click="changeLockType(LockType.Locked)">
<div>
<MdiCheck v-if="selectedView?.lock_type === LockType.Locked" />
<span v-else />
<div>
<MdiLockOutlineIcon />
Locked View
<div class="nc-subtitle">No one can edit the view configuration until it is unlocked.</div>
</div>
</div>
</div>
</a-menu-item>
<a-menu-item>
<div class="nc-menu-item" @click="changeLockType(LockType.Personal)">
<div>
<MdiCheck v-if="selectedView?.lock_type === LockType.Personal" />
<span v-else />
<div>
<MdiAccountIcon />
Personal view
<div class="nc-subtitle">
Only you can edit the view configuration. Other collaborators personal views are hidden by
default.
</div>
</div>
</div>
</div>
<!-- </div> -->
<!-- </div> -->
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="download">
<template #title>
<div v-t="['c:navdraw:preview-as']" class="nc-project-menu-item group">
<MdiDownload class="group-hover:text-pink-500" />
Download
<div class="flex-1" />
<MaterialSymbolsChevronRightRounded
class="transform group-hover:(scale-115 text-pink-500) text-xl text-gray-400"
/>
</div>
</template>
<template #expandIcon></template>
<a-menu-item>
<div v-t="['a:actions:download-csv']" class="nc-menu-item" @click="exportFile(ExportTypes.CSV)">
<MdiDownloadOutline class="text-gray-500" />
<!-- Download as CSV -->
{{ $t('activity.downloadCSV') }}
</div>
</a-menu-item>
<a-menu-item>
<div v-t="['a:actions:download-excel']" class="nc-menu-item" @click="exportFile(ExportTypes.EXCEL)">
<MdiDownloadOutline class="text-gray-500" />
<!-- Download as XLSX -->
{{ $t('activity.downloadExcel') }}
</div>
</a-menu-item>
</a-sub-menu>
<a-sub-menu key="upload">
<template #title>
<div v-t="['c:navdraw:preview-as']" class="nc-project-menu-item group">
<MdiDownload class="group-hover:text-pink-500" />
Download
<div class="flex-1" />
<MaterialSymbolsChevronRightRounded
class="transform group-hover:(scale-115 text-pink-500) text-xl text-gray-400"
/>
</div>
</template>
<template #expandIcon></template>
<a-menu-item>
<div
v-if="isUIAllowed('csvImport') && !isView && !isPublicView"
v-t="['a:actions:upload-csv']"
class="nc-menu-item"
:class="{ disabled: isLocked }"
@click="!isLocked ? (quickImportDialog = true) : {}"
>
<MdiUploadOutline class="text-gray-500" />
<!-- Upload CSV -->
{{ $t('activity.uploadCSV') }}
</div>
</a-menu-item>
</a-sub-menu>
<!-- <div class="bg-gray-50 py-2 shadow-lg !border"> -->
<!-- <div> -->
<!-- <div v-t="['a:actions:download-csv']" class="nc-menu-item" @click="exportFile(ExportTypes.CSV)"> -->
<!-- <MdiDownloadOutline class="text-gray-500" /> -->
<!-- &lt;!&ndash; Download as CSV &ndash;&gt; -->
<!-- {{ $t('activity.downloadCSV') }} -->
<!-- </div> -->
<!-- <div v-t="['a:actions:download-excel']" class="nc-menu-item" @click="exportFile(ExportTypes.EXCEL)"> -->
<!-- <MdiDownloadOutline class="text-gray-500" /> -->
<!-- &lt;!&ndash; Download as XLSX &ndash;&gt; -->
<!-- {{ $t('activity.downloadExcel') }} -->
<!-- </div> -->
<!-- <div -->
<!-- v-if="isUIAllowed('csvImport') && !isView && !isPublicView" -->
<!-- v-t="['a:actions:upload-csv']" -->
<!-- class="nc-menu-item" -->
<!-- :class="{ disabled: isLocked }" -->
<!-- @click="!isLocked ? (quickImportDialog = true) : {}" -->
<!-- > -->
<!-- <MdiUploadOutline class="text-gray-500" /> -->
<!-- &lt;!&ndash; Upload CSV &ndash;&gt; -->
<!-- {{ $t('activity.uploadCSV') }} -->
<!-- </div> -->
<!-- <div -->
<!-- v-if="isUIAllowed('SharedViewList') && !isView && !isPublicView" -->
<!-- v-t="['a:actions:shared-view-list']" -->
<!-- class="nc-menu-item" -->
<!-- @click="sharedViewListDlg = true" -->
<!-- > -->
<!-- <MdiViewListOutline class="text-gray-500" /> -->
<!-- &lt;!&ndash; Shared View List &ndash;&gt; -->
<!-- {{ $t('activity.listSharedView') }} -->
<!-- </div> -->
<!-- <div -->
<!-- v-if="isUIAllowed('webhook') && !isView && !isPublicView" -->
<!-- v-t="['c:actions:webhook']" -->
<!-- class="nc-menu-item" -->
<!-- @click="showWebhookDrawer = true" -->
<!-- > -->
<!-- <MdiHook class="text-gray-500" /> -->
<!-- {{ $t('objects.webhooks') }} -->
<!-- </div> -->
<!-- </div> -->
<!-- </div> -->
<a-menu-item>
<div
v-if="isUIAllowed('SharedViewList') && !isView && !isPublicView"
v-t="['a:actions:shared-view-list']"
@click="sharedViewListDlg = true"
class="py-2 flex gap-2"
>
<MdiViewListOutline class="text-gray-500" />
<!-- Shared View List -->
{{ $t('activity.listSharedView') }}
</div>
</a-menu-item>
<a-menu-item>
<div
v-if="isUIAllowed('webhook') && !isView && !isPublicView"
v-t="['c:actions:webhook']"
class="py-2 flex gap-2"
@click="showWebhookDrawer = true"
>
<MdiHook class="text-gray-500" />
{{ $t('objects.webhooks') }}
</div>
</a-menu-item>
</a-menu-item-group>
</a-menu>
</template>
</a-dropdown>
<DlgQuickImport v-if="quickImportDialog" v-model="quickImportDialog" import-type="csv" :import-only="true" />
<WebhookDrawer v-if="showWebhookDrawer" v-model="showWebhookDrawer" />
<a-modal v-model:visible="sharedViewListDlg" title="Shared view list" width="max(900px,60vw)" :footer="null">
<SmartsheetToolbarSharedViewList v-if="sharedViewListDlg" />
</a-modal>
</div>
</template>

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

@ -1,13 +1,21 @@
<script setup lang="ts"> <script setup lang="ts">
import { IsPublicInj, useSmartsheetStoreOrThrow } from '#imports' import { IsPublicInj, useSmartsheetStoreOrThrow } from '#imports'
import AddRow from '~/components/smartsheet/sidebar/toolbar/AddRow.vue'
import Reload from '~/components/smartsheet/sidebar/toolbar/Reload.vue'
import ToggleDrawer from '~/components/smartsheet/sidebar/toolbar/ToggleDrawer.vue'
const { isGrid, isForm, isGallery } = useSmartsheetStoreOrThrow() const { isGrid, isForm, isGallery } = useSmartsheetStoreOrThrow()
const { allowCSVDownload } = useSharedView() const { allowCSVDownload } = useSharedView()
const isPublic = inject(IsPublicInj, ref(false)) const isPublic = inject(IsPublicInj, ref(false))
const {isOpen} =useSidebar()
</script> </script>
<template> <template>
<div class="nc-table-toolbar w-full py-1 flex gap-1 items-center h-[var(--toolbar-height)] px-2 border-b" style="z-index: 7"> <div class="nc-table-toolbar w-full py-1 flex gap-1 items-center h-[var(--toolbar-height)] px-2 border-b" style="z-index: 7">
<SmartsheetToolbarViewActions v-if="isGrid || isGallery" :show-system-fields="false" class="ml-1" />
<SmartsheetToolbarFieldsMenu v-if="isGrid || isGallery" :show-system-fields="false" class="ml-1" /> <SmartsheetToolbarFieldsMenu v-if="isGrid || isGallery" :show-system-fields="false" class="ml-1" />
<SmartsheetToolbarColumnFilterMenu v-if="isGrid || isGallery" /> <SmartsheetToolbarColumnFilterMenu v-if="isGrid || isGallery" />
@ -16,9 +24,21 @@ const isPublic = inject(IsPublicInj, ref(false))
<SmartsheetToolbarShareView v-if="(isForm || isGrid) && !isPublic" /> <SmartsheetToolbarShareView v-if="(isForm || isGrid) && !isPublic" />
<SmartsheetToolbarMoreActions v-if="(isGrid && !isPublic) || (isGrid && isPublic && allowCSVDownload)" />
<!-- <SmartsheetToolbarMoreActions v-if="(isGrid && !isPublic) || (isGrid && isPublic && allowCSVDownload)" />-->
<div class="flex-1" /> <div class="flex-1" />
<SmartsheetToolbarSearchData v-if="(isGrid || isGallery) && !isPublic" class="shrink mr-2" />
<Reload/>
<AddRow/>
<SmartsheetToolbarSearchData v-if="(isGrid || isGallery) && !isPublic" class="shrink mr-2 ml-2" />
<ToggleDrawer v-if="!isOpen"/>
</div> </div>
</template> </template>

37
packages/nc-gui-v2/components/smartsheet/sidebar/MenuBottom.vue

@ -109,24 +109,25 @@ function onOpenModal(type: ViewTypes, title = '') {
</a-menu-item> </a-menu-item>
</div> </div>
<SmartsheetSidebarMenuApiSnippet v-model="showApiSnippet" /> <div class="flex-1"></div>
<!-- <SmartsheetSidebarMenuApiSnippet v-model="showApiSnippet" />-->
<div class="flex-auto justify-end flex flex-col gap-3 mt-3">
<button <!-- <div class="flex-auto justify-end flex flex-col gap-3 mt-3">-->
v-if="isUIAllowed('virtualViewsCreateOrEdit')" <!-- <button-->
class="flex items-center gap-2 w-full mx-3 px-4 py-3 rounded border transform translate-x-4 hover:(translate-x-0 shadow-lg) transition duration-150 ease !text-xs nc-webhook-btn" <!-- v-if="isUIAllowed('virtualViewsCreateOrEdit')"-->
@click="onWebhooks" <!-- class="flex items-center gap-2 w-full mx-3 px-4 py-3 rounded border transform translate-x-4 hover:(translate-x-0 shadow-lg) transition duration-150 ease !text-xs nc-webhook-btn"-->
> <!-- @click="onWebhooks"-->
<mdi-hook />{{ $t('objects.webhooks') }} <!-- >-->
</button> <!-- <mdi-hook />{{ $t('objects.webhooks') }}-->
<!-- </button>-->
<button
class="flex items-center gap-2 w-full mx-3 px-4 py-3 rounded border transform translate-x-4 hover:(translate-x-0 shadow-lg) transition duration-150 ease !text-xs" <!-- <button-->
@click="onApiSnippet" <!-- class="flex items-center gap-2 w-full mx-3 px-4 py-3 rounded border transform translate-x-4 hover:(translate-x-0 shadow-lg) transition duration-150 ease !text-xs"-->
> <!-- @click="onApiSnippet"-->
<mdi-xml />Get API Snippet <!-- >-->
</button> <!-- <mdi-xml />Get API Snippet-->
</div> <!-- </button>-->
<!-- </div>-->
<general-flipping-card class="my-4 lg:my-6 min-h-[100px]" :triggers="['click', { duration: 15000 }]"> <general-flipping-card class="my-4 lg:my-6 min-h-[100px]" :triggers="['click', { duration: 15000 }]">
<template #front> <template #front>

2
packages/nc-gui-v2/components/smartsheet/sidebar/MenuTop.vue

@ -170,7 +170,7 @@ function onDeleted() {
</script> </script>
<template> <template>
<h3 class="pt-3 px-3 text-xs text-gray-500 font-semibold">{{ $t('objects.views') }}</h3> <!-- <h3 class="pt-3 px-3 text-xs text-gray-500 font-semibold">{{ $t('objects.views') }}</h3>-->
<a-menu ref="menuRef" :class="{ dragging }" class="nc-views-menu" :selected-keys="selected"> <a-menu ref="menuRef" :class="{ dragging }" class="nc-views-menu" :selected-keys="selected">
<RenameableMenuItem <RenameableMenuItem

16
packages/nc-gui-v2/components/smartsheet/sidebar/toolbar/index.vue

@ -45,18 +45,22 @@ const { isOpen } = useSidebar({ storageKey: 'nc-right-sidebar' })
<div class="dot" /> <div class="dot" />
</template> </template>
<h3 class="pt-3 px-3 text-xs text-gray-500 font-semibold">{{ $t('objects.views') }}</h3>
<LockMenu v-if="isUIAllowed('view-type')" @click.stop /> <!-- <LockMenu v-if="isUIAllowed('view-type')" @click.stop />-->
<div v-if="isUIAllowed('view-type')" class="dot" /> <!-- <div v-if="isUIAllowed('view-type')" class="dot" />-->
<Reload @click.stop /> <!-- <Reload @click.stop />-->
<!-- <div class="dot" />-->
<!-- <AddRow v-if="isUIAllowed('xcDatatableEditable')" @click.stop />-->
<!-- <div :class="{ 'w-[calc(100%_+_16px)] h-[1px] bg-gray-200 mt-1 -ml-1': !isOpen, 'dot': isOpen }" />-->
<div class="dot" />
<AddRow v-if="isUIAllowed('xcDatatableEditable')" @click.stop />
<div :class="{ 'w-[calc(100%_+_16px)] h-[1px] bg-gray-200 mt-1 -ml-1': !isOpen, 'dot': isOpen }" />
<ToggleDrawer /> <ToggleDrawer />

9
packages/nc-gui-v2/components/tabs/Smartsheet.vue

@ -87,6 +87,13 @@ watch(isLocked, (nextValue) => (treeViewIsLockedInj.value = nextValue), { immedi
</template> </template>
</div> </div>
<SmartsheetSidebar v-if="meta" /> <SmartsheetSidebar class="nc-right-sidebar" v-if="meta" />
</div> </div>
</template> </template>
<style scoped>
:deep(.nc-right-sidebar.ant-layout-sider-collapsed) {
@apply !w-0 !max-w-0 !min-w-0 overflow-x-hidden;
}
</style>

Loading…
Cancel
Save