Browse Source

feat: new expanded view

pull/6464/head
DarkPhoenix2704 1 year ago
parent
commit
9dafef1bfa
  1. 12
      packages/nc-gui/assets/nc-icons/table.svg
  2. 5
      packages/nc-gui/components.d.ts
  3. 260
      packages/nc-gui/components/smartsheet/expanded-form/Comments.vue
  4. 275
      packages/nc-gui/components/smartsheet/expanded-form/index.vue
  5. 2
      packages/nc-gui/utils/iconUtils.ts

12
packages/nc-gui/assets/nc-icons/table.svg

@ -0,0 +1,12 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1409_68546)">
<path d="M12.3571 5.96842L4.64282 10.4219" stroke="#1F293A" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="1.15184" width="9.06208" height="9.06208" rx="1.335" transform="matrix(0.866044 -0.499967 0.866044 0.499967 -0.345705 8.77119)" stroke="#1F293A" stroke-width="1.33"/>
<path d="M4 6.33984L11.7143 10.7933" stroke="#1F293A" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1409_68546">
<rect width="16" height="16" fill="white" transform="translate(0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 712 B

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

@ -80,6 +80,7 @@ declare module '@vue/runtime-core' {
CilFullscreenExit: typeof import('~icons/cil/fullscreen-exit')['default']
ClaritySuccessLine: typeof import('~icons/clarity/success-line')['default']
IcBaselineMoreVert: typeof import('~icons/ic/baseline-more-vert')['default']
Icon: typeof import('~icons/ic/on')['default']
IcOutlineInsertDriveFile: typeof import('~icons/ic/outline-insert-drive-file')['default']
IcRoundEdit: typeof import('~icons/ic/round-edit')['default']
IcRoundKeyboardArrowDown: typeof import('~icons/ic/round-keyboard-arrow-down')['default']
@ -103,8 +104,10 @@ declare module '@vue/runtime-core' {
MaterialSymbolsVisibility: typeof import('~icons/material-symbols/visibility')['default']
MaterialSymbolsVisibilityOff: typeof import('~icons/material-symbols/visibility-off')['default']
MaterialSymbolsWarning: typeof import('~icons/material-symbols/warning')['default']
MdiAccordionUp: typeof import('~icons/mdi/accordion-up')['default']
MdiAccount: typeof import('~icons/mdi/account')['default']
MdiAccountCircleOutline: typeof import('~icons/mdi/account-circle-outline')['default']
MdiAccountCircleOutlines: typeof import('~icons/mdi/account-circle-outlines')['default']
MdiAccountSupervisorOutline: typeof import('~icons/mdi/account-supervisor-outline')['default']
MdiAlpha: typeof import('~icons/mdi/alpha')['default']
MdiAppleKeyboardShift: typeof import('~icons/mdi/apple-keyboard-shift')['default']
@ -122,6 +125,7 @@ declare module '@vue/runtime-core' {
MdiChevronDown: typeof import('~icons/mdi/chevron-down')['default']
MdiChevronLeft: typeof import('~icons/mdi/chevron-left')['default']
MdiChevronRight: typeof import('~icons/mdi/chevron-right')['default']
MdiChevronUp: typeof import('~icons/mdi/chevron-up')['default']
MdiCircleMedium: typeof import('~icons/mdi/circle-medium')['default']
MdiClose: typeof import('~icons/mdi/close')['default']
MdiCodeTags: typeof import('~icons/mdi/code-tags')['default']
@ -143,6 +147,7 @@ declare module '@vue/runtime-core' {
MdiMenuDown: typeof import('~icons/mdi/menu-down')['default']
MdiMicrosoftTeams: typeof import('~icons/mdi/microsoft-teams')['default']
MdiMoonFull: typeof import('~icons/mdi/moon-full')['default']
MdiMoreVert: typeof import('~icons/mdi/more-vert')['default']
MdiPlus: typeof import('~icons/mdi/plus')['default']
MdiReload: typeof import('~icons/mdi/reload')['default']
MdiRocketLaunchOutline: typeof import('~icons/mdi/rocket-launch-outline')['default']

260
packages/nc-gui/components/smartsheet/expanded-form/Comments.vue

@ -1,43 +1,24 @@
<script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core'
import type { AuditType } from 'nocodb-sdk'
import {
enumColor,
iconMap,
ref,
timeAgo,
useCopy,
useExpandedFormStoreOrThrow,
useGlobal,
useI18n,
useRoles,
watch,
} from '#imports'
const { loadCommentsAndLogs, commentsAndLogs, isCommentsLoading, commentsOnly, saveComment, isYou, comment, updateComment } =
import { Icon } from '@iconify/vue'
import { ref, timeAgo, useExpandedFormStoreOrThrow, useGlobal, useRoles, watch } from '#imports'
const { loadCommentsAndLogs, commentsAndLogs, isCommentsLoading, saveComment, comment, updateComment } =
useExpandedFormStoreOrThrow()
const commentsWrapperEl = ref<HTMLDivElement>()
await loadCommentsAndLogs()
const showBorder = ref(false)
const { copy } = useCopy()
const { t } = useI18n()
const { user } = useGlobal()
const tab = ref<'comments' | 'audits'>('comments')
const { isUIAllowed } = useRoles()
const hasEditPermission = computed(() => isUIAllowed('commentEdit'))
// currently, edit option is disable on purpose
// since the current update wouldn't keep track of the previous values
// need history of edit feature in order to enable it back
const disableEditOption = ref(true)
const editLog = ref<AuditType>()
const isEditing = ref<boolean>(false)
@ -89,36 +70,26 @@ onKeyStroke('Enter', (event) => {
}
})
const _contextMenu = ref(false)
const contextMenu = computed({
get: () => _contextMenu.value,
set: (val) => {
if (hasEditPermission.value) {
_contextMenu.value = val
}
},
})
async function copyComment(val: string) {
if (!val) return
try {
await copy(val)
message.success(t('msg.success.commentCopied'))
} catch (e: any) {
message.error(e.message)
}
}
const comments = computed(() => commentsAndLogs.value.filter((log) => log.op_type === 'COMMENT'))
function editComment(log: AuditType) {
editLog.value = log
isEditing.value = true
}
const value = computed({
get() {
return editLog.value.description.substring(editLog.value.description.indexOf(':') + 1) ?? ''
},
set(val) {
if (!editLog.value) return
editLog.value.description = val
},
})
watch(
commentsAndLogs,
() => {
// todo: replace setTimeout
setTimeout(() => {
if (commentsWrapperEl.value) commentsWrapperEl.value.scrollTop = commentsWrapperEl.value?.scrollHeight
}, 200)
@ -128,61 +99,126 @@ watch(
</script>
<template>
<div class="h-full flex flex-col w-full bg-gray-100 p-2">
<div ref="commentsWrapperEl" class="flex-1 min-h-[100px] overflow-y-auto scrollbar-thin-dull p-2 space-y-2">
<a-skeleton v-if="isCommentsLoading" type="list-item-avatar-two-line@8" />
<template v-else-if="commentsAndLogs.length === 0">
<div class="flex flex-col text-center justify-center h-full">
<div class="text-center text-3xl text-gray-300">
<MdiChatProcessingOutline />
</div>
<div class="font-bold text-center my-1 text-gray-400">Start a conversation</div>
<div class="text-gray-400">
NocoDB allows you to inquire, monitor progress updates, and collaborate with your team members.
</div>
<div class="flex flex-col w-full bg-gray-50 rounded-lg">
<div class="bg-white rounded-t-lg border-gray-200 border-b-1">
<div class="flex flex-row m-2 p-1 bg-gray-100 rounded-lg">
<div
class="tab flex-1 transition-all cursor-pointer rounded-lg"
:class="{
'bg-white shadow text-brand-500 hover:text-brand-500': tab === 'comments',
}"
@click="tab = 'comments'"
>
<div class="tab-title nc-tab">Comments</div>
</div>
</template>
<template v-else>
<div v-for="(log, idx) of commentsAndLogs" :key="log.id">
<a-dropdown :trigger="['contextmenu']" :overlay-class-name="`nc-dropdown-comment-context-menu-${idx}`">
<div
class="tab flex-1 transition-all cursor-pointer rounded-lg"
:class="{
'bg-white shadow text-brand-500 hover:text-brand-500': tab === 'audits',
}"
@click="tab = 'audits'"
>
<div class="tab-title nc-tab">Audits</div>
</div>
</div>
</div>
<div>
<div
v-if="tab === 'comments'"
ref="commentsWrapperEl"
class="flex flex-col m-1 p-1 !h-[calc(100vh-300px)] overflow-y-scroll nc-scrollbar-md space-y-2"
>
<a-skeleton v-if="isCommentsLoading" type="list-item-avatar-two-line@8" />
<template v-else-if="commentsAndLogs.length === 0">
<div class="flex flex-col text-center justify-center h-full">
<div class="text-center text-3xl text-gray-300">
<MdiChatProcessingOutline />
</div>
<div class="font-bold text-center my-1 text-gray-400">Start a conversation</div>
<div class="text-gray-400">
NocoDB allows you to inquire, monitor progress updates, and collaborate with your team members.
</div>
</div>
</template>
<template v-else>
<div v-for="(log, idx) of comments" :key="log.id">
<div class="bg-white rounded-xl border-1 gap-3 border-gray-200">
<div class="flex flex-col p-4 gap-3">
<div class="flex justify-between">
<div class="flex font-bold items-center gap-2">
<MdiAccountCircleOutline class="row-span-2 h-8 w-8" />
<span class="truncate max-w-42">
{{ log.user ?? 'Shared base' }}
</span>
</div>
<NcButton
v-if="log.user === user.email && !editLog"
type="secondary"
class="!px-2"
size="sm"
@click="editComment(log)"
>
<Icon class="iconify text-gray-800" icon="lucide:pen" />
</NcButton>
</div>
<textarea
v-if="log.id === editLog?.id"
:ref="focusInput"
v-model="value"
rows="6"
class="px-2 py-1 rounded-lg border-none nc-scrollbar-md bg-white outline-gray-200"
@keydown.stop="onKeyDown($event)"
/>
<div v-else class="text-sm text-gray-700">
{{ log.description.substring(log.description.indexOf(':') + 1) }}
</div>
<div v-if="log.id === editLog?.id" class="flex justify-end gap-1">
<NcButton type="secondary" size="sm" @click="onCancel"> Cancel </NcButton>
<NcButton size="sm" @click="onEditComment"> Save </NcButton>
</div>
<div v-if="log.id !== editLog?.id" class="text-xs text-gray-500">
{{ log.created_at !== log.updated_at ? `Edited ${timeAgo(log.updated_at)}` : timeAgo(log.created_at) }}
</div>
</div>
</div>
<!-- <a-dropdown :trigger="['contextmenu']" :overlay-class-name="`nc-dropdown-comment-context-menu-${idx}`">
<div class="flex gap-1 text-xs">
<component
:is="iconMap.accountCircle"
class="row-span-2"
:class="isYou(log.user) ? 'text-pink-600' : 'text-blue-600 '"
:is="iconMap.accountCircle"
class="row-span-2"
:class="isYou(log.user) ? 'text-pink-600' : 'text-blue-600 '"
/>
<div class="flex-1">
<p class="mb-1 caption edited-text text-[10px] text-gray-500">
{{ isYou(log.user) ? 'You' : log.user == null ? 'Shared base' : log.user }}
{{ log.op_type === 'COMMENT' ? 'commented' : log.op_sub_type === 'INSERT' ? 'created' : 'edited' }}
</p>
<div v-if="log.op_type === 'COMMENT'">
<a-input
v-if="log.id === editLog?.id"
:ref="focusInput"
v-model:value="editLog.description"
@blur="onCancel"
@keydown.stop="onKeyDown($event)"
v-if="log.id === editLog?.id"
:ref="focusInput"
v-model:value="editLog.description"
@blur="onCancel"
@keydown.stop="onKeyDown($event)"
/>
<p
v-else
class="block caption my-2 nc-chip w-full min-h-20px p-2 rounded"
:style="{ backgroundColor: enumColor.light[2] }"
v-else
class="block caption my-2 nc-chip w-full min-h-20px p-2 rounded"
:style="{ backgroundColor: enumColor.light[2] }"
>
<!--
retrieve the comment part from the audit description
`The following comment has been created: foo` -> `foo`
-->
{{ log.description.substring(log.description.indexOf(':') + 1) }}
</p>
</div>
<p v-else-if="log.details" v-dompurify-html="log.details" class="caption my-3" style="word-break: break-all" />
retrieve the comment part from the audit description
`The following comment has been created: foo` -> `foo`
{{ log.description.substring(log.description.indexOf(':') + 1) }}
</p>
</div>
<p v-else-if="log.details" v-dompurify-html="log.details" class="caption my-3" style="word-break: break-all" />
<p v-else>{{ log.description }}</p>
<p class="time text-right text-[10px] mb-0 mt-1 text-gray-500">
{{ timeAgo(log.created_at) }}
</p>
@ -196,60 +232,46 @@ watch(
{{ t('general.copy') }}
</div>
</a-menu-item>
<a-menu-item v-if="log.user === user.email && !disableEditOption" key="edit-comment" @click="editComment(log)">
<a-menu-item v-if="log.user === user.email " key="edit-comment" ">
<div v-e="['a:comment:edit']" class="nc-project-menu-item">
{{ t('general.edit') }}
</div>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
</template>
</div>
<div class="border-1 my-2 w-full" />
</a-dropdown> -->
</div>
</template>
</div>
<div class="p-0">
<div class="flex justify-center">
<!-- Comments only -->
<!-- <div class="flex justify-center">
<a-checkbox v-model:checked="commentsOnly" v-e="['c:row-expand:comment-only']" @change="loadCommentsAndLogs">
{{ $t('labels.commentsOnly') }}
<span class="text-[11px] text-gray-500" />
</a-checkbox>
</div>
</div> -->
<div v-if="hasEditPermission" class="shrink mt-2 flex">
<div v-if="hasEditPermission && tab === 'comments'" class="shrink mt-2 p-2 rounded-b-xl border-t-1 bg-white gap-1 flex">
<a-input
v-model:value="comment"
class="!text-xs nc-comment-box"
ghost
:class="{ focus: showBorder }"
@focusin="showBorder = true"
@focusout="showBorder = false"
class="!rounded-lg border-1 bg-white !px-4 !py-2 !border-gray-200 nc-comment-box"
placeholder="Start typing..."
@keyup.enter.prevent="saveComment"
>
<template #addonBefore>
<div class="flex items-center">
<component :is="iconMap.accountCircle" class="text-lg text-pink-700" small @click="saveComment" />
</div>
</template>
<template #suffix>
<component :is="iconMap.returnKey" v-if="comment" class="text-sm" small @click="saveComment" />
</template>
</a-input>
<NcButton type="secondary" size="medium" @click="saveComment">
<Icon class="iconify text-gray-800" icon="lucide:send" />
</NcButton>
</div>
</div>
</div>
</template>
<style scoped>
:deep(.red.lighten-4) {
@apply bg-red-100;
}
:deep(.green.lighten-4) {
@apply bg-green-100;
.tab .tab-title {
@apply min-w-0 flex justify-center items-center py-1;
word-break: 'keep-all';
white-space: 'nowrap';
display: 'inline';
}
</style>

275
packages/nc-gui/components/smartsheet/expanded-form/index.vue

@ -3,6 +3,8 @@ import type { TableType, ViewType } from 'nocodb-sdk'
import { isLinksOrLTAR, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import type { Ref } from 'vue'
import MdiChevronDown from '~icons/mdi/chevron-down'
import TableIcon from '~icons/nc-icons/table'
import {
CellClickHookInj,
FieldsInj,
@ -62,6 +64,8 @@ const isPublic = inject(IsPublicInj, ref(false))
const { isUIAllowed } = useRoles()
const reloadTrigger = inject(ReloadRowDataHookInj, createEventHook())
// override cell click hook to avoid unexpected behavior at form fields
provide(CellClickHookInj, undefined)
@ -89,12 +93,15 @@ provide(MetaInj, meta)
const {
commentsDrawer,
changedColumns,
deleteRowById,
displayValue,
state: rowState,
isNew,
loadRow: _loadRow,
primaryKey,
saveRowAndStay,
syncLTARRefs,
save,
save: _save,
} = useProvideExpandedFormStore(meta, row)
const duplicatingRowInProgress = ref(false)
@ -220,6 +227,17 @@ const addNewRow = () => {
}, 500)
}
const save = async () => {
if (isNew.value) {
const data = await _save(rowState.value)
await syncLTARRefs(data)
reloadTrigger?.trigger()
} else {
await _save()
reloadTrigger?.trigger()
}
}
// attach keyboard listeners to switch between rows
// using alt + left/right arrow keys
useActiveKeyupListener(
@ -241,7 +259,7 @@ useActiveKeyupListener(
e.stopPropagation()
if (isNew.value) {
const data = await save(rowState.value)
const data = await _save(rowState.value)
await syncLTARRefs(data)
reloadHook?.trigger(null)
} else {
@ -276,7 +294,7 @@ useActiveKeyupListener(
okText: 'Save',
cancelText: 'Discard',
onOk: async () => {
const data = await save(rowState.value)
const data = await _save(rowState.value)
await syncLTARRefs(data)
reloadHook?.trigger(null)
addNewRow()
@ -292,6 +310,19 @@ useActiveKeyupListener(
},
{ immediate: true },
)
const showDeleteRowModal = ref(false)
const onDeleteRowClick = () => {
showDeleteRowModal.value = true
}
const onConfirmDeleteRowClick = async () => {
showDeleteRowModal.value = false
await deleteRowById(primaryKey.value)
await reloadTrigger.trigger()
message.success('Row deleted')
}
</script>
<script lang="ts">
@ -301,59 +332,98 @@ export default {
</script>
<template>
<a-drawer
<a-modal
:key="key"
v-model:visible="isExpanded"
:footer="null"
:width="commentsDrawer && isUIAllowed('commentList') ? 'min(90vw,900px)' : 'min(90vw,700px)'"
:body-style="{ 'padding': 0, 'display': 'flex', 'flex-direction': 'column' }"
:width="commentsDrawer && isUIAllowed('commentList') ? 'min(90vw,1000px)' : 'min(90vw,800px)'"
:body-style="{ padding: 0 }"
:closable="false"
class="nc-drawer-expanded-form"
:class="{ active: isExpanded }"
>
<SmartsheetExpandedFormHeader :view="props.view" @cancel="onClose" @duplicate-row="onDuplicateRow" />
<div :key="key" class="!bg-gray-50 rounded flex-1">
<div class="flex h-full nc-form-wrapper items-stretch min-h-[max(70vh,100%)]">
<div class="flex-1 overflow-auto scrollbar-thin-dull nc-form-fields-container relative">
<template v-if="props.showNextPrevIcons">
<a-tooltip v-if="!props.firstRow" placement="bottom">
<template #title>
{{ $t('labels.prevRow') }}
<GeneralShortcutLabel class="justify-center" :keys="['Alt', '←']" />
</template>
<GeneralIcon icon="chevronLeft" class="cursor-pointer nc-prev-arrow" @click="$emit('prev')" />
</a-tooltip>
<a-tooltip v-if="!props.lastRow" placement="bottom">
<template #title>
{{ $t('labels.nextRow') }}
<GeneralShortcutLabel class="justify-center" :keys="['Alt', '→']" />
</template>
<GeneralIcon icon="chevronRight" class="cursor-pointer nc-next-arrow" @click="onNext" />
</a-tooltip>
<div class="flex w-full items-center relative pb-2 justify-between">
<div class="flex gap-3">
<NcButton v-if="props.showNextPrevIcons" type="secondary" size="small" class="nc-prev-arrow" @click="$emit('prev')">
<MdiChevronUp class="text-md text-gray-700" />
</NcButton>
<NcButton v-if="!props.lastRow" type="secondary" size="small" class="nc-next-arrow" @click="onNext">
<MdiChevronDown class="text-md text-gray-700" />
</NcButton>
<div v-if="displayValue" class="flex items-center font-bold text-gray-800 text-xl">
{{ displayValue }}
</div>
<div class="bg-gray-100 px-2 gap-1 flex items-center rounded-md text-gray-800">
<TableIcon class="w-6 h-6 text-sm" />
All {{ meta.title }}
</div>
</div>
<div class="flex gap-1">
<NcDropdown v-if="!isNew">
<NcButton type="secondary" size="small" class="nc-expand-form-more-actions">
<MdiMoreVert class="text-md text-gray-700" />
</NcButton>
<template #overlay>
<NcMenu>
<NcMenuItem v-if="!isNew" class="text-gray-700" @click="_loadRow()">
<div v-e="['c:row-expand:reload']" class="flex gap-2 items-center">
<component :is="iconMap.reload" class="cursor-pointer" />
{{ $t('general.reload') }}
</div>
</NcMenuItem>
<NcMenuItem v-if="isUIAllowed('dataEdit') && !isNew" class="text-gray-700" @click="!isNew && onDuplicateRow">
<div v-e="['c:row-expand:duplicate']" class="flex gap-2 items-center">
<component :is="iconMap.copy" class="cursor-pointer nc-duplicate-row" />
Duplicate record
</div>
</NcMenuItem>
<a-menu-divider class="my-1" />
<NcMenuItem
v-if="isUIAllowed('dataEdit') && !isNew"
v-e="['c:row-expand:delete']"
class="!text-red-500"
@click="!isNew && onDeleteRowClick()"
>
<component :is="iconMap.delete" class="cursor-pointer nc-delete-row" />
Delete record
</NcMenuItem>
</NcMenu>
</template>
<div class="w-[500px] mx-auto">
<div v-if="duplicatingRowInProgress" class="flex items-center justify-center h-[100px]">
<a-spin size="large" />
</div>
<div
v-for="(col, i) of fields"
v-else
v-show="isFormula(col) || !isVirtualCol(col) || !isNew || isLinksOrLTAR(col)"
:key="col.title"
class="mt-2 py-2"
:class="`nc-expand-col-${col.title}`"
:data-testid="`nc-expand-col-${col.title}`"
>
<LazySmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" />
</NcDropdown>
<NcButton type="secondary" size="small" @click="onClose">
<MdiClose class="text-md text-gray-700" />
</NcButton>
</div>
</div>
<div class="flex flex-row w-full gap-4">
<div
class="fle relative w-full flex-col"
:class="{
'!w-4/6': !isNew,
}"
>
<div
class="flex flex-col h-[calc(100vh-200px)] !pb-12 nc-scrollbar-md overflow-y-scroll items-center w-full bg-white border-1 border-gray-200 rounded-xl p-4"
>
<div
v-for="(col, i) of fields"
v-show="isFormula(col) || !isVirtualCol(col) || !isNew || isLinksOrLTAR(col)"
:key="col.title"
class="mt-2 py-2"
:class="`nc-expand-col-${col.title}`"
:data-testid="`nc-expand-col-${col.title}`"
>
<div class="flex flex-row">
<div class="w-[12rem] scale-110">
<LazySmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" />
<LazySmartsheetHeaderCell v-else :column="col" />
<LazySmartsheetHeaderCell v-else :column="col" />
</div>
<LazySmartsheetDivDataCell
v-if="col.title"
:ref="i ? null : (el: any) => (cellWrapperEl = el)"
class="!bg-white rounded px-1 min-h-[35px] flex items-center mt-2 relative"
class="!bg-white rounded-lg !w-[20rem] border-1 border-gray-200 px-1 min-h-[35px] flex items-center relative"
>
<LazySmartsheetVirtualCell v-if="isVirtualCol(col)" v-model="row.row[col.title]" :row="row" :column="col" />
@ -368,34 +438,36 @@ export default {
/>
</LazySmartsheetDivDataCell>
</div>
<div v-if="hiddenFields.length > 0" class="my-4">
<div class="flex items-center py-4">
<div class="flex-grow h-px mr-1 bg-gray-100"></div>
<a-button
class="!rounded-md flex items-center flex-shrink-1 focus:!border-[#d9d9d9] focus:!text-gray-500 hover:text-blue"
@click="toggleHiddenFields"
>
{{ showHiddenFields ? `Hide ${hiddenFields.length} hidden` : `Show ${hiddenFields.length} hidden` }}
{{ hiddenFields.length > 1 ? `fields` : `field` }}
<MdiChevronDown class="ml-1" :class="showHiddenFields ? 'transform rotate-180' : ''" />
</a-button>
<div class="flex-grow ml-1 h-px bg-gray-100"></div>
</div>
<div
v-for="(col, i) of hiddenFields"
v-show="(isFormula(col) || !isVirtualCol(col) || !isNew || isLinksOrLTAR(col)) && showHiddenFields"
:key="col.title"
class="mt-2 py-2"
:class="`nc-expand-col-${col.title}`"
:data-testid="`nc-expand-col-${col.title}`"
>
<LazySmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" />
</div>
<div v-if="hiddenFields.length > 0" class="flex items-center py-3">
<div class="flex-grow h-px mr-1 bg-gray-100"></div>
<NcButton type="secondary" size="small" class="flex-shrink-1 !text-sm" @click="toggleHiddenFields">
{{ showHiddenFields ? `Hide ${hiddenFields.length} hidden` : `Show ${hiddenFields.length} hidden` }}
{{ hiddenFields.length > 1 ? `fields` : `field` }}
<MdiChevronDown class="ml-1" :class="showHiddenFields ? 'transform rotate-180' : ''" />
</NcButton>
<div class="flex-grow h-px mr-1 bg-gray-100"></div>
</div>
<div v-if="hiddenFields.length > 0 && showHiddenFields" class="mb-3">
<div
v-for="(col, i) of hiddenFields"
v-show="isFormula(col) || !isVirtualCol(col) || !isNew || isLinksOrLTAR(col)"
:key="col.title"
class="mt-2 py-2"
:class="`nc-expand-col-${col.title}`"
:data-testid="`nc-expand-col-${col.title}`"
>
<div class="flex flex-row">
<div class="w-[12rem] scale-110">
<LazySmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" />
<LazySmartsheetHeaderCell v-else :column="col" />
<LazySmartsheetHeaderCell v-else :column="col" />
</div>
<LazySmartsheetDivDataCell
:ref="i ? null : (el) => (cellWrapperEl = el)"
class="!bg-white rounded px-1 min-h-[35px] flex items-center mt-2 relative"
v-if="col.title"
:ref="i ? null : (el: any) => (cellWrapperEl = el)"
class="!bg-white rounded-lg !w-[20rem] border-1 border-gray-200 px-1 min-h-[35px] flex items-center relative"
>
<LazySmartsheetVirtualCell v-if="isVirtualCol(col)" v-model="row.row[col.title]" :row="row" :column="col" />
@ -413,54 +485,33 @@ export default {
</div>
</div>
</div>
<div
v-if="!isNew"
class="nc-comments-drawer min-w-0 min-h-full max-h-full"
:class="{ active: commentsDrawer && isUIAllowed('commentList') }"
v-if="isUIAllowed('dataEdit')"
class="w-full absolute bottom-0 bg-white flex justify-end border-1 border-gray-200 p-2 rounded-b-lg"
>
<div class="h-full">
<LazySmartsheetExpandedFormComments v-if="commentsDrawer && isUIAllowed('commentList')" />
</div>
<NcButton type="primary" size="medium" @click="save"> Save </NcButton>
</div>
</div>
<div
v-if="!isNew"
class="nc-comments-drawer border-1 border-gray-200 w-2/6 rounded-lg min-w-0"
:class="{ active: commentsDrawer && isUIAllowed('commentList') }"
>
<LazySmartsheetExpandedFormComments v-if="commentsDrawer && isUIAllowed('commentList')" />
</div>
</div>
</a-drawer>
</template>
</a-modal>
<style scoped lang="scss">
:deep(input, select, textarea) {
@apply !bg-white;
}
:deep(.ant-modal-body) {
@apply !bg-gray-50;
}
.nc-comments-drawer {
@apply w-0 transition-width ease-in-out duration-200;
overflow: hidden;
&.active {
@apply w-[250px] border-left-1;
}
}
.nc-form-wrapper {
max-height: max(calc(100vh - 65px), 600px);
height: max-content !important;
}
.nc-prev-arrow,
.nc-next-arrow {
@apply w-7 h-7 flex items-center justify-center absolute opacity-70 rounded-full transition-transform transition-background transition-opacity transform bg-white hover:(bg-gray-200) active:(scale-125 opacity-100) !text-xl;
}
<GeneralModal v-model:visible="showDeleteRowModal" class="!w-[25rem]">
<div class="p-4">
<div class="prose-xl font-bold self-center">Delete row ?</div>
.nc-prev-arrow {
@apply left-4 top-4;
}
<div class="mt-4">Are you sure you want to delete this row?</div>
</div>
<div class="flex flex-row gap-x-2 mt-1 pt-1.5 justify-end p-4">
<NcButton @click="onConfirmDeleteRowClick">{{ $t('general.confirm') }} </NcButton>
</div>
</GeneralModal>
</template>
.nc-next-arrow {
@apply right-4 top-4;
}
</style>
<style scoped lang="scss"></style>

2
packages/nc-gui/utils/iconUtils.ts

@ -327,7 +327,7 @@ export const iconMap = {
edit: MaterialSymbolsEdit,
lookup: h('span', { class: 'material-symbols' }, 'search'),
text: h('span', { class: 'material-symbols' }, 'text_fields'),
longText: h('span', { class: 'material-symbols' }, 'text_format'),
longText: h('span', { class: 'material-symbols' }, 'view_headline'),
clock: h('span', { class: 'material-symbols' }, 'access_time'),
web: h('span', { class: 'material-symbols' }, 'web'),
webhook: h('span', { class: 'material-symbols' }, 'webhook'),

Loading…
Cancel
Save