Browse Source

fix: Added new view context menu

pull/6888/head
Muhammed Mustafa 11 months ago
parent
commit
8f41c836dd
  1. 2
      packages/nc-gui/assets/nc-icons/check.svg
  2. 14
      packages/nc-gui/components/smartsheet/toolbar/ExportSubActions.vue
  3. 28
      packages/nc-gui/components/smartsheet/toolbar/LockType.vue
  4. 258
      packages/nc-gui/components/smartsheet/toolbar/OpenedViewAction.vue
  5. 25
      packages/nc-gui/components/smartsheet/toolbar/ViewInfo.vue

2
packages/nc-gui/assets/nc-icons/check.svg

@ -1,5 +1,5 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="check">
<path id="Vector" d="M13.3333 4.5L5.99996 11.8333L2.66663 8.5" stroke="#40444D" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector" d="M13.3333 4.5L5.99996 11.8333L2.66663 8.5" stroke="currentColor" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 275 B

After

Width:  |  Height:  |  Size: 280 B

14
packages/nc-gui/components/smartsheet/toolbar/ExportSubActions.vue

@ -99,19 +99,21 @@ const exportFile = async (exportType: ExportTypes) => {
</script>
<template>
<a-menu-item>
<div v-e="['a:download:csv']" class="nc-base-menu-item" @click="exportFile(ExportTypes.CSV)">
<div class="flex py-3 px-4 font-bold uppercase text-xs text-gray-500">Download Data</div>
<NcMenuItem>
<div v-e="['a:download:csv']" class="nc-base-menu-item !py-0" @click="exportFile(ExportTypes.CSV)">
<component :is="iconMap.csv" />
<!-- Download as CSV -->
{{ $t('activity.downloadCSV') }}
</div>
</a-menu-item>
</NcMenuItem>
<a-menu-item>
<div v-e="['a:download:excel']" class="nc-base-menu-item" @click="exportFile(ExportTypes.EXCEL)">
<NcMenuItem>
<div v-e="['a:download:excel']" class="nc-base-menu-item !py-0" @click="exportFile(ExportTypes.EXCEL)">
<component :is="iconMap.excel" />
<!-- Download as XLSX -->
{{ $t('activity.downloadExcel') }}
</div>
</a-menu-item>
</NcMenuItem>
</template>

28
packages/nc-gui/components/smartsheet/toolbar/LockType.vue

@ -29,29 +29,31 @@ const selectedView = inject(ActiveViewInj)
</script>
<template>
<div class="nc-locked-menu-item min-w-50" @click="emit('select', type)">
<div class="nc-locked-menu-item !px-1 min-w-50 text-gray-800" @click="emit('select', type)">
<div :class="{ 'show-tick': !hideTick }">
<div class="flex items-center gap-2 flex-grow">
<component :is="types[type].icon" class="text-gray-800 !w-4 !h-4" />
<div class="flex flex-col">
{{ $t(types[type].title) }}
<div v-if="!hideTick" class="nc-subtitle max-w-120 text-sm text-gray-500 whitespace-normal">
{{ $t(types[type].subtitle) }}
<div class="flex flex-col gap-y-1">
<div class="flex items-center gap-2 flex-grow">
<component :is="types[type].icon" class="!w-4 !min-w-4 text-inherit !h-4" />
<div class="flex">
{{ $t(types[type].title) }}
</div>
<div class="flex flex-grow"></div>
<template v-if="!hideTick">
<GeneralIcon v-if="selectedView?.lock_type === type" icon="check" class="!text-brand-500" />
<span v-else />
</template>
</div>
<div v-if="!hideTick" class="nc-subtitle max-w-120 text-sm text-gray-500 whitespace-normal ml-6">
{{ $t(types[type].subtitle) }}
</div>
</div>
<template v-if="!hideTick">
<GeneralIcon v-if="selectedView?.lock_type === type" icon="check" />
<span v-else />
</template>
</div>
</div>
</template>
<style scoped lang="scss">
.nc-locked-menu-item > div {
@apply py-2 items-center;
@apply !py-0 items-center;
&.show-tick {
@apply flex gap-2;

258
packages/nc-gui/components/smartsheet/toolbar/OpenedViewAction.vue

@ -0,0 +1,258 @@
<script lang="ts" setup>
import type { ViewType } from 'nocodb-sdk'
import { ViewTypes } from 'nocodb-sdk'
import { LockType } from '~/lib'
import UploadIcon from '~icons/nc-icons/upload'
import DownloadIcon from '~icons/nc-icons/download'
const { activeView, views } = storeToRefs(useViewsStore())
const { loadViews, navigateToView } = useViewsStore()
const { isMobileMode } = useGlobal()
const { activeTable } = storeToRefs(useTablesStore())
const { base, isSharedBase } = storeToRefs(useBase())
const { refreshCommandPalette } = useCommandPalette()
const { t } = useI18n()
const { $api, $e } = useNuxtApp()
const isPublicView = inject(IsPublicInj, ref(false))
const isLocked = inject(IsLockedInj, ref(false))
const { isSqlView } = useSmartsheetStoreOrThrow()
const lockType = computed(() => (activeView.value?.lock_type as LockType) || LockType.Collaborative)
// TODO: add 'json' when it's ready
const quickImportDialogTypes: QuickImportDialogType[] = ['csv', 'excel']
const isViewIdCopied = ref(false)
const quickImportDialogs: Record<(typeof quickImportDialogTypes)[number], Ref<boolean>> = quickImportDialogTypes.reduce(
(acc: any, curr) => {
acc[curr] = ref(false)
return acc
},
{},
) as Record<QuickImportDialogType, Ref<boolean>>
const { isUIAllowed } = useRoles()
async function changeLockType(type: LockType) {
$e('a:grid:lockmenu', { lockType: type })
if (!activeView.value) return
if (type === 'personal') {
// Coming soon
return message.info(t('msg.toast.futureRelease'))
}
try {
activeView.value.lock_type = type
await $api.dbView.update(activeView.value.id as string, {
lock_type: type,
})
message.success(`Successfully Switched to ${type} view`)
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
}
const { copy } = useCopy()
const onViewIdCopy = async () => {
await copy(activeView.value!.id!)
isViewIdCopied.value = true
}
/** Duplicate a view */
// todo: This is not really a duplication, maybe we need to implement a true duplication?
function onDuplicate() {
const isOpen = ref(true)
const { close } = useDialog(resolveComponent('DlgViewCreate'), {
'modelValue': isOpen,
'title': activeView.value!.title,
'type': activeView.value!.type as ViewTypes,
'tableId': activeTable.value!.id,
'selectedViewId': activeView.value!.id,
'views': views,
'onUpdate:modelValue': closeDialog,
'onCreated': async (view: ViewType) => {
closeDialog()
refreshCommandPalette()
await loadViews({
force: true,
tableId: activeTable.value!.id!,
})
navigateToView({
view,
tableId: activeTable.value!.id!,
baseId: base.value.id!,
hardReload: view.type === ViewTypes.FORM,
})
$e('a:view:create', { view: view.type })
},
})
function closeDialog() {
isOpen.value = false
close(1000)
}
}
</script>
<template>
<NcDropdown>
<div
class="truncate nc-active-view-title !hover:(bg-gray-100 text-gray-800) ml-0.25 pl-1 pr-0.25 rounded-md py-1 cursor-pointer"
:class="{
'max-w-2/5': !isSharedBase && !isMobileMode && activeView?.is_default,
'max-w-3/5': !isSharedBase && !isMobileMode && !activeView?.is_default,
'max-w-1/2': isMobileMode,
'text-gray-500': activeView?.is_default,
'text-gray-800 font-medium': !activeView?.is_default,
}"
>
<span
class="truncate xs:pl-1.25 text-inherit"
:class="{
'max-w-28/100': !isMobileMode,
}"
>
{{ activeView?.is_default ? $t('title.defaultView') : activeView?.title }}
</span>
<GeneralIcon icon="arrowDown" class="ml-1" />
</div>
<template #overlay>
<NcMenu class="min-w-72">
<div class="flex items-center justify-between py-2 px-2">
<div class="flex text-xs font-bold text-gray-500 ml-1">VIEW ID: {{ activeView?.id }}</div>
<NcTooltip>
<template #title>Click to copy View ID</template>
<NcButton size="xsmall" type="secondary" @click="onViewIdCopy">
<GeneralIcon v-if="isViewIdCopied" icon="check" />
<GeneralIcon v-else else icon="copy" />
</NcButton>
</NcTooltip>
</div>
<NcDivider />
<NcMenuItem>
<GeneralIcon icon="edit" />
Rename View
</NcMenuItem>
<NcMenuItem @click="onDuplicate">
<GeneralIcon icon="copy" />
Duplicate View
</NcMenuItem>
<NcDivider />
<NcMenuItem-group>
<template v-if="isUIAllowed('csvTableImport') && !isPublicView && !isSqlView">
<NcSubMenu key="upload">
<template #title>
<div v-e="['c:navdraw:preview-as']" class="nc-base-menu-item group">
<UploadIcon class="w-4 h-4" />
{{ $t('general.upload') }}
</div>
</template>
<template #expandIcon></template>
<div class="flex py-3 px-4 font-bold uppercase text-xs text-gray-500">Upload Data</div>
<template v-for="(dialog, type) in quickImportDialogs">
<NcMenuItem v-if="isUIAllowed(`${type}TableImport`) && !isPublicView" :key="type">
<div
v-e="[`a:upload:${type}`]"
class="nc-base-menu-item"
:class="{ disabled: isLocked }"
@click="!isLocked ? (dialog.value = true) : {}"
>
<component :is="iconMap.upload" />
{{ `${$t('general.upload')} ${type.toUpperCase()}` }}
</div>
</NcMenuItem>
</template>
</NcSubMenu>
</template>
<NcSubMenu key="download">
<template #title>
<div v-e="['c:download']" class="nc-base-menu-item group">
<DownloadIcon class="w-4 h-4" />
{{ $t('general.download') }}
</div>
</template>
<template #expandIcon></template>
<LazySmartsheetToolbarExportSubActions />
</NcSubMenu>
<NcDivider />
<NcSubMenu
v-if="isUIAllowed('viewCreateOrEdit')"
key="lock-type"
class="scrollbar-thin-dull max-h-90vh overflow-auto !py-0"
>
<template #title>
<div v-e="['c:navdraw:preview-as']" class="flex flex-row items-center gap-x-3">
<div>View Settings</div>
<div class="nc-base-menu-item flex !flex-shrink group !py-1 !px-1 rounded-md bg-brand-50">
<LazySmartsheetToolbarLockType
hide-tick
:type="lockType"
class="flex nc-view-actions-lock-type !text-brand-500 !flex-shrink"
/>
</div>
<div class="flex flex-grow"></div>
</div>
</template>
<template #expandIcon></template>
<div class="flex py-3 px-4 font-semibold uppercase text-xs text-gray-500">View Settings</div>
<NcMenuItem class="nc-view-action-lock-subaction" @click="changeLockType(LockType.Collaborative)">
<LazySmartsheetToolbarLockType :type="LockType.Collaborative" />
</NcMenuItem>
<NcMenuItem @click="changeLockType(LockType.Locked)">
<LazySmartsheetToolbarLockType :type="LockType.Locked" />
</NcMenuItem>
</NcSubMenu>
</NcMenuItem-group>
</NcMenu>
</template>
</NcDropdown>
</template>
<style lang="scss" scoped>
.nc-base-menu-item {
@apply !py-0;
}
.nc-view-actions-lock-type {
@apply !min-w-0;
}
</style>
<style lang="scss">
.nc-view-actions-lock-type > div {
@apply !py-0;
}
.nc-view-action-lock-subaction {
@apply !min-w-82;
}
</style>

25
packages/nc-gui/components/smartsheet/toolbar/ViewInfo.vue

@ -121,7 +121,7 @@ const openedBaseUrl = computed(() => {
</div>
</template>
<div v-if="!isMobileMode" class="px-1 text-gray-500">/</div>
<div v-if="!isMobileMode" class="pl-1 text-gray-500">/</div>
<template v-if="!(isMobileMode && activeView?.is_default)">
<LazyGeneralEmojiPicker v-if="isMobileMode" :emoji="activeView?.meta?.icon" readonly size="xsmall">
@ -130,28 +130,7 @@ const openedBaseUrl = computed(() => {
</template>
</LazyGeneralEmojiPicker>
<NcTooltip
class="truncate nc-active-view-title"
:class="{
'max-w-2/5': !isSharedBase && !isMobileMode && activeView?.is_default,
'max-w-3/5': !isSharedBase && !isMobileMode && !activeView?.is_default,
'max-w-1/2': isMobileMode,
}"
>
<template #title>
{{ activeView?.is_default ? $t('title.defaultView') : activeView?.title }}
</template>
<span
class="truncate xs:pl-1.25"
:class="{
'max-w-28/100': !isMobileMode,
'text-gray-500': activeView?.is_default,
'text-gray-800 font-medium': !activeView?.is_default,
}"
>
{{ activeView?.is_default ? $t('title.defaultView') : activeView?.title }}
</span>
</NcTooltip>
<SmartsheetToolbarOpenedViewAction />
</template>
<LazySmartsheetToolbarReload v-if="openedViewsTab === 'view' && !isMobileMode" />

Loading…
Cancel
Save