diff --git a/packages/nc-gui/components/ai/PromptWithFields.vue b/packages/nc-gui/components/ai/PromptWithFields.vue
index 3b56693836..219f6cd597 100644
--- a/packages/nc-gui/components/ai/PromptWithFields.vue
+++ b/packages/nc-gui/components/ai/PromptWithFields.vue
@@ -3,6 +3,7 @@ import Placeholder from '@tiptap/extension-placeholder'
import StarterKit from '@tiptap/starter-kit'
import Mention from '@tiptap/extension-mention'
import { EditorContent, useEditor } from '@tiptap/vue-3'
+import tippy from 'tippy.js'
import { type ColumnType, UITypes } from 'nocodb-sdk'
import FieldList from '~/helpers/tiptapExtensions/mention/FieldList'
import suggestion from '~/helpers/tiptapExtensions/mention/suggestion.ts'
@@ -15,6 +16,7 @@ const props = withDefaults(
promptFieldTagClassName?: string
suggestionIconClassName?: string
placeholder?: string
+ readOnly?: boolean
}>(),
{
options: () => [],
@@ -26,6 +28,7 @@ const props = withDefaults(
* @example: :placeholder="`Enter prompt here...\n\neg : Categorise this {Notes}`"
*/
placeholder: 'Write your prompt here...',
+ readOnly: false,
},
)
@@ -38,7 +41,9 @@ const vModel = computed({
},
})
-const { autoFocus } = toRefs(props)
+const { autoFocus, readOnly } = toRefs(props)
+
+const debouncedLoadMentionFieldTagTooltip = useDebounceFn(loadMentionFieldTagTooltip, 1000)
const editor = useEditor({
content: vModel.value,
@@ -55,18 +60,25 @@ const editor = useEditor({
...suggestion(FieldList),
items: ({ query }) => {
if (query.length === 0) return props.options ?? []
- return props.options?.filter((o) => o.title?.toLowerCase()?.includes(query.toLowerCase())) ?? []
+ return (
+ props.options?.filter(
+ (o) =>
+ o.title?.toLowerCase()?.includes(query.toLowerCase()) || `${o.title?.toLowerCase()}}` === query.toLowerCase(),
+ ) ?? []
+ )
},
char: '{',
allowSpaces: true,
},
renderHTML: ({ node }) => {
+ const matchedOption = props.options?.find((option) => option.title === node.attrs.id)
+ const isAttachment = matchedOption?.uidt === UITypes.Attachment
return [
'span',
{
- class: `prompt-field-tag ${
- props.options?.find((option) => option.title === node.attrs.id)?.uidt === UITypes.Attachment ? '!bg-green-200' : ''
- } ${props.promptFieldTagClassName}`,
+ 'class': `prompt-field-tag ${isAttachment ? '!bg-green-200' : ''} ${props.promptFieldTagClassName}`,
+ 'style': 'max-width: 100px; white-space: nowrap; overflow: hidden; display: inline-block; text-overflow: ellipsis;', // Enforces truncation
+ 'data-tooltip': node.attrs.id, // Tooltip content
},
`${node.attrs.id}`,
]
@@ -93,8 +105,10 @@ const editor = useEditor({
text = text.trim()
vModel.value = text
+
+ debouncedLoadMentionFieldTagTooltip()
},
- editable: true,
+ editable: !readOnly.value,
autofocus: autoFocus.value,
editorProps: { scrollThreshold: 100 },
})
@@ -141,15 +155,60 @@ onMounted(async () => {
}, 100)
}
})
+
+const tooltipInstances: any[] = []
+
+function loadMentionFieldTagTooltip() {
+ document.querySelectorAll('.nc-ai-prompt-with-fields .prompt-field-tag').forEach((el) => {
+ const tooltip = Object.values(el.attributes).find((attr) => attr.name === 'data-tooltip')
+ if (!tooltip || el.scrollWidth <= el.clientWidth) return
+ // Show tooltip only on truncate
+ const instance = tippy(el, {
+ content: `
${tooltip.value}
`,
+ placement: 'top',
+ allowHTML: true,
+ arrow: true,
+ animation: 'fade',
+ duration: 0,
+ maxWidth: '200px',
+ })
+
+ tooltipInstances.push(instance)
+ })
+}
+
+onMounted(() => {
+ debouncedLoadMentionFieldTagTooltip()
+})
+
+onBeforeUnmount(() => {
+ tooltipInstances.forEach((instance) => instance?.destroy())
+ tooltipInstances.length = 0
+})
-
+
-
+
@@ -160,11 +219,11 @@ onMounted(async () => {
@apply relative;
.nc-prompt-with-field-suggestion-btn {
- @apply absolute top-[1px] right-[1px];
+ @apply absolute top-[2px] right-[1px];
}
.prompt-field-tag {
- @apply bg-gray-100 rounded-md px-1;
+ @apply bg-gray-100 rounded-md px-1 align-middle;
}
.ProseMirror {
@@ -172,6 +231,10 @@ onMounted(async () => {
resize: vertical;
min-width: 100%;
max-height: min(800px, calc(100vh - 200px)) !important;
+
+ & > p {
+ @apply mr-3;
+ }
}
.ProseMirror-focused {
diff --git a/packages/nc-gui/components/ai/Settings.vue b/packages/nc-gui/components/ai/Settings.vue
index 2b9d66db1c..20b3e650fe 100644
--- a/packages/nc-gui/components/ai/Settings.vue
+++ b/packages/nc-gui/components/ai/Settings.vue
@@ -7,9 +7,11 @@ const props = withDefaults(
workspaceId: string
scope?: string
showTooltip?: boolean
+ isEditColumn?: boolean
}>(),
{
showTooltip: true,
+ isEditColumn: false,
},
)
@@ -19,6 +21,8 @@ const vFkIntegrationId = useVModel(props, 'fkIntegrationId', emits)
const vModel = useVModel(props, 'model', emits)
+const { isEditColumn } = toRefs(props)
+
// const vRandomness = useVModel(props, 'randomness', emits)
const { $api } = useNuxtApp()
@@ -29,7 +33,7 @@ const lastIntegrationId = ref(null)
const isDropdownOpen = ref(false)
-const availableModels = ref([])
+const availableModels = ref<{ value: string; label: string }[]>([])
const isLoadingAvailableModels = ref(false)
@@ -50,10 +54,10 @@ const onIntegrationChange = async (newFkINtegrationId?: string) => {
try {
const response = await $api.integrations.endpoint(newFkINtegrationId, 'availableModels', {})
- availableModels.value = response as string[]
+ availableModels.value = (response || []) as { value: string; label: string }[]
if (!vModel.value && availableModels.value.length > 0) {
- vModel.value = availableModels.value[0]
+ vModel.value = availableModels.value[0].value
}
} catch (error) {
console.error(error)
@@ -63,6 +67,10 @@ const onIntegrationChange = async (newFkINtegrationId?: string) => {
}
onMounted(async () => {
+ if (isEditColumn.value) {
+ return
+ }
+
if (!vFkIntegrationId.value) {
if (aiIntegrations.value.length > 0 && aiIntegrations.value[0].id) {
vFkIntegrationId.value = aiIntegrations.value[0].id
@@ -72,6 +80,10 @@ onMounted(async () => {
}
} else {
lastIntegrationId.value = vFkIntegrationId.value
+
+ if (!vModel.value || !availableModels.value.length) {
+ onIntegrationChange()
+ }
}
})
@@ -111,6 +123,7 @@ onMounted(async () => {
v-model:value="vFkIntegrationId"
class="w-full nc-select-shadow nc-ai-input"
size="middle"
+ placeholder="- select integration -"
@change="onIntegrationChange"
>
@@ -150,20 +163,21 @@ onMounted(async () => {
v-model:value="vModel"
class="w-full nc-select-shadow nc-ai-input"
size="middle"
+ placeholder="- select model -"
:disabled="!vFkIntegrationId || availableModels.length === 0"
:loading="isLoadingAvailableModels"
>
-
+
- {{ md }}
+ {{ md.label }}
- {{ md }}
+ {{ md.label }}
@@ -198,4 +212,10 @@ onMounted(async () => {
-
+
diff --git a/packages/nc-gui/components/cell/AI.vue b/packages/nc-gui/components/cell/AI.vue
index aa5ea1e2c6..ff2e8bbfe5 100644
--- a/packages/nc-gui/components/cell/AI.vue
+++ b/packages/nc-gui/components/cell/AI.vue
@@ -13,6 +13,10 @@ const { generateRows, generatingRows, generatingColumnRows, aiIntegrations } = u
const { row } = useSmartsheetRowStoreOrThrow()
+const { isUIAllowed } = useRoles()
+
+const isPublic = inject(IsPublicInj, ref(false))
+
const meta = inject(MetaInj, ref())
const column = inject(ColumnInj) as Ref<
@@ -40,9 +44,7 @@ const isAiEdited = ref(false)
const isFieldAiIntegrationAvailable = computed(() => {
const fkIntegrationId = column.value?.colOptions?.fk_integration_id
- if (!fkIntegrationId) return false
-
- return ncIsArrayIncludes(aiIntegrations.value, fkIntegrationId, 'id')
+ return !!fkIntegrationId
})
const pk = computed(() => {
@@ -58,7 +60,7 @@ const generate = async () => {
ncIsString(column.value.colOptions?.output_column_ids) && column.value.colOptions.output_column_ids.split(',').length > 1
? column.value.colOptions.output_column_ids.split(',')
: []
- const outputColumns = outputColumnIds.map((id) => meta.value?.columnsById[id])
+ const outputColumns = outputColumnIds.map((id) => meta.value?.columnsById?.[id]).filter(Boolean)
generatingRows.value.push(pk.value)
generatingColumnRows.value.push(column.value.id)
@@ -76,11 +78,18 @@ const generate = async () => {
}
} else {
const obj: AIRecordType = resRow[column.value.title!]
+
if (obj && typeof obj === 'object') {
vModel.value = obj
setTimeout(() => {
isAiEdited.value = false
}, 100)
+ } else {
+ vModel.value = {
+ ...(ncIsObject(vModel.value) ? vModel.value : {}),
+ isStale: false,
+ value: resRow[column.value.title!],
+ }
}
}
}
@@ -99,10 +108,16 @@ const isLoading = computed(() => {
})
const handleSave = () => {
+ vModel.value = { ...vModel.value }
+
emits('save')
}
const debouncedSave = useDebounceFn(handleSave, 1000)
+
+const isDisabledAiButton = computed(() => {
+ return !isFieldAiIntegrationAvailable.value || isLoading.value || isPublic.value || !isUIAllowed('dataEdit')
+})
@@ -113,20 +128,15 @@ const debouncedSave = useDebounceFn(handleSave, 1000)
'justify-center': isGrid && !isExpandedForm,
}"
>
-
+
{{ aiIntegrations.length ? $t('tooltip.aiIntegrationReConfigure') : $t('tooltip.aiIntegrationAddAndReConfigure') }}
-
@@ -147,10 +157,19 @@ const debouncedSave = useDebounceFn(handleSave, 1000)
diff --git a/packages/nc-gui/components/cell/TextArea.vue b/packages/nc-gui/components/cell/TextArea.vue
index 9256520dae..c51602a5c5 100644
--- a/packages/nc-gui/components/cell/TextArea.vue
+++ b/packages/nc-gui/components/cell/TextArea.vue
@@ -14,6 +14,8 @@ const props = defineProps<{
const emits = defineEmits(['update:modelValue', 'update:isAiEdited', 'generate', 'close'])
+const meta = inject(MetaInj, ref())
+
const column = inject(ColumnInj)
const editEnabled = inject(EditModeInj, ref(false))
@@ -34,7 +36,9 @@ const readOnly = inject(ReadonlyInj, ref(false))
const { showNull, user } = useGlobal()
-const { aiLoading, aiIntegrations } = useNocoAi()
+const { currentRow } = useSmartsheetRowStoreOrThrow()
+
+const { aiLoading, aiIntegrations, generatingRows, generatingColumnRows } = useNocoAi()
const baseStore = useBase()
@@ -93,6 +97,19 @@ const aiWarningRef = ref()
const { height: aiWarningRefHeight } = useElementSize(aiWarningRef)
+const rowId = computed(() => {
+ return extractPkFromRow(currentRow.value?.row, meta.value!.columns!)
+})
+
+const isAiGenerating = computed(() => {
+ return !!(
+ rowId.value &&
+ column?.value.id &&
+ generatingRows.value.includes(rowId.value) &&
+ generatingColumnRows.value.includes(column.value.id)
+ )
+})
+
watch(isVisible, () => {
if (isVisible.value) {
setTimeout(() => {
@@ -406,8 +423,8 @@ watch(
@selectstart.capture.stop
@mousedown.stop
/>
-
-
+
+
@@ -419,8 +436,8 @@ watch(
-
-
Generated by AI
+
+ Generated by AI
Edited by you
Edited by you
@@ -458,12 +475,13 @@ watch(
theme="ai"
size="xs"
:disabled="!isFieldAiIntegrationAvailable"
- :loading="aiLoading"
+ :loading="isAiGenerating"
@click.stop="generate"
>
-
+
+ Re-generating...
Re-generate
@@ -488,10 +506,8 @@ watch(
{{ vModel }}
-
- {{ $t('title.expand') }}
-
-
-
-
+
+ {{ isAiGenerating ? 'Re-generating...' : 'Re-generate' }}
+
+
+
+
+
+
+
+
+ {{ $t('title.expand') }}
+
+
+
+
+
-
- Re-generate
+
+ {{ isAiGenerating ? 'Re-generating...' : 'Re-generate' }}
-
+
@@ -679,7 +723,7 @@ textarea:focus {
diff --git a/packages/nc-gui/components/smartsheet/column/UITypesOptionsWithSearch.vue b/packages/nc-gui/components/smartsheet/column/UITypesOptionsWithSearch.vue
index 9c8adf6993..cc2dc7d4e0 100644
--- a/packages/nc-gui/components/smartsheet/column/UITypesOptionsWithSearch.vue
+++ b/packages/nc-gui/components/smartsheet/column/UITypesOptionsWithSearch.vue
@@ -20,7 +20,7 @@ const filteredOptions = computed(
() =>
options.value?.filter(
(c) =>
- !(c.name === 'AIButton' && !isFeatureEnabled(FEATURE_FLAG.AI_FEATURES)) &&
+ !((c.name === 'AIButton' || c.name === 'AIPrompt') && !isFeatureEnabled(FEATURE_FLAG.AI_FEATURES)) &&
(c.name.toLowerCase().includes(searchQuery.value.toLowerCase()) ||
(UITypesName[c.name] && UITypesName[c.name].toLowerCase().includes(searchQuery.value.toLowerCase()))),
) ?? [],
@@ -126,7 +126,7 @@ watch(
'hover:bg-gray-100 cursor-pointer': !isDisabledUIType(option.name),
'bg-gray-100 nc-column-list-option-active': activeFieldIndex === index && !isDisabledUIType(option.name),
'!text-gray-400 cursor-not-allowed': isDisabledUIType(option.name),
- '!text-nc-content-purple-dark': option.name === 'AIButton',
+ '!text-nc-content-purple-dark': option.name === 'AIButton' || option.name === 'AIPrompt',
},
]"
:data-testid="option.name"
diff --git a/packages/nc-gui/components/smartsheet/details/Fields.vue b/packages/nc-gui/components/smartsheet/details/Fields.vue
index 9dbd53d930..f6dafbe49c 100644
--- a/packages/nc-gui/components/smartsheet/details/Fields.vue
+++ b/packages/nc-gui/components/smartsheet/details/Fields.vue
@@ -1037,6 +1037,10 @@ const onClickCopyFieldUrl = async (field: ColumnType) => {
await copy(field.id!)
isFieldIdCopied.value = true
+
+ await ncDelay(5000)
+
+ isFieldIdCopied.value = false
}
const keys = useMagicKeys()
diff --git a/packages/nc-gui/components/smartsheet/expanded-form/index.vue b/packages/nc-gui/components/smartsheet/expanded-form/index.vue
index dec44ec27c..f92d9fb778 100644
--- a/packages/nc-gui/components/smartsheet/expanded-form/index.vue
+++ b/packages/nc-gui/components/smartsheet/expanded-form/index.vue
@@ -327,6 +327,10 @@ const copyRecordUrl = async () => {
)
isRecordLinkCopied.value = true
+
+ await ncDelay(5000)
+
+ isRecordLinkCopied.value = false
}
const saveChanges = async () => {
diff --git a/packages/nc-gui/components/smartsheet/grid/GroupByTable.vue b/packages/nc-gui/components/smartsheet/grid/GroupByTable.vue
index a8cd49ace6..a593c281c2 100644
--- a/packages/nc-gui/components/smartsheet/grid/GroupByTable.vue
+++ b/packages/nc-gui/components/smartsheet/grid/GroupByTable.vue
@@ -276,6 +276,7 @@ async function deleteSelectedRowsWrapper() {
+
import {
- ButtonActionsType,
type ButtonType,
type ColumnReqType,
type ColumnType,
@@ -8,6 +7,7 @@ import {
UITypes,
type ViewType,
ViewTypes,
+ isAIPromptCol,
isCreatedOrLastModifiedByCol,
isCreatedOrLastModifiedTimeCol,
isLinksOrLTAR,
@@ -1024,8 +1024,8 @@ const isSelectedOnlyAI = computed(() => {
if (selectedRange.start.col === selectedRange.end.col) {
const field = fields.value[selectedRange.start.col]
return {
- enabled: field.uidt === UITypes.Button && (field?.colOptions as ButtonType)?.type === ButtonActionsType.Ai,
- disabled: !ncIsArrayIncludes(aiIntegrations.value, (field?.colOptions as ButtonType)?.fk_integration_id, 'id'),
+ enabled: isAIPromptCol(field) || isAiButton(field),
+ disabled: !(field?.colOptions as ButtonType)?.fk_integration_id,
}
}
@@ -1048,9 +1048,7 @@ const generateAIBulk = async () => {
let outputColumnIds = [field.id]
- const isAiButton = field.uidt === UITypes.Button && (field?.colOptions as ButtonType)?.type === ButtonActionsType.Ai
-
- if (isAiButton) {
+ if (isAiButton(field)) {
outputColumnIds =
ncIsString(field.colOptions?.output_column_ids) && field.colOptions.output_column_ids.split(',').length > 0
? field.colOptions.output_column_ids.split(',')
@@ -2248,13 +2246,13 @@ watch(vSelectedAllRecords, (selectedAll) => {
diff --git a/packages/nc-gui/components/smartsheet/grid/Table.vue b/packages/nc-gui/components/smartsheet/grid/Table.vue
index fb8b1cb447..bda48a7293 100644
--- a/packages/nc-gui/components/smartsheet/grid/Table.vue
+++ b/packages/nc-gui/components/smartsheet/grid/Table.vue
@@ -3,9 +3,9 @@ import axios from 'axios'
import { nextTick } from '@vue/runtime-core'
import type { ButtonType, ColumnReqType, ColumnType, PaginatedType, TableType, ViewType } from 'nocodb-sdk'
import {
- ButtonActionsType,
UITypes,
ViewTypes,
+ isAIPromptCol,
isCreatedOrLastModifiedByCol,
isCreatedOrLastModifiedTimeCol,
isLinksOrLTAR,
@@ -852,8 +852,8 @@ const isSelectedOnlyAI = computed(() => {
if (selectedRange.start.col === selectedRange.end.col) {
const field = fields.value[selectedRange.start.col]
return {
- enabled: field.uidt === UITypes.Button && (field?.colOptions as ButtonType)?.type === ButtonActionsType.Ai,
- disabled: !ncIsArrayIncludes(aiIntegrations.value, (field?.colOptions as ButtonType)?.fk_integration_id, 'id'),
+ enabled: isAIPromptCol(field) || isAiButton(field),
+ disabled: !(field?.colOptions as ButtonType)?.fk_integration_id,
}
}
@@ -876,9 +876,7 @@ const generateAIBulk = async () => {
let outputColumnIds = [field.id]
- const isAiButton = field.uidt === UITypes.Button && (field?.colOptions as ButtonType)?.type === ButtonActionsType.Ai
-
- if (isAiButton) {
+ if (isAiButton(field)) {
outputColumnIds =
ncIsString(field.colOptions?.output_column_ids) && field.colOptions.output_column_ids.split(',').length > 0
? field.colOptions.output_column_ids.split(',')
@@ -2139,13 +2137,13 @@ onKeyStroke('ArrowDown', onDown)
diff --git a/packages/nc-gui/components/smartsheet/header/Cell.vue b/packages/nc-gui/components/smartsheet/header/Cell.vue
index cf07c2f92e..d32cd46342 100644
--- a/packages/nc-gui/components/smartsheet/header/Cell.vue
+++ b/packages/nc-gui/components/smartsheet/header/Cell.vue
@@ -43,9 +43,16 @@ const editColumnDropdown = ref(false)
const columnOrder = ref | null>(null)
const columnTypeName = computed(() => {
- if (column.value.uidt === UITypes.LongText && parseProp(column?.value?.meta)?.richMode) {
- return UITypesName.RichText
+ if (column.value.uidt === UITypes.LongText) {
+ if (parseProp(column.value?.meta)?.richMode) {
+ return UITypesName.RichText
+ }
+
+ if (parseProp(column.value?.meta)?.[LongTextAiMetaProp]) {
+ return UITypesName.AIPrompt
+ }
}
+
return column.value.uidt ? UITypesName[column.value.uidt] : ''
})
diff --git a/packages/nc-gui/components/smartsheet/header/CellIcon.ts b/packages/nc-gui/components/smartsheet/header/CellIcon.ts
index 0923872ecd..2ce6e8ac5a 100644
--- a/packages/nc-gui/components/smartsheet/header/CellIcon.ts
+++ b/packages/nc-gui/components/smartsheet/header/CellIcon.ts
@@ -20,6 +20,8 @@ const renderIcon = (column: ColumnType, abstractType: any) => {
return iconMap.cellSingleSelect
} else if (isBoolean(column, abstractType)) {
return iconMap.cellCheckbox
+ } else if (isAI(column)) {
+ return iconMap.cellAi
} else if (isTextArea(column)) {
return iconMap.cellLongText
} else if (isEmail(column)) {
@@ -51,8 +53,6 @@ const renderIcon = (column: ColumnType, abstractType: any) => {
return iconMap.cellUser
}
return iconMap.cellUser
- } else if (isAI(column)) {
- return iconMap.cellAi
} else if (isInt(column, abstractType) || isFloat(column, abstractType)) {
return iconMap.cellNumber
} else if (isString(column, abstractType)) {
diff --git a/packages/nc-gui/components/smartsheet/header/Menu.vue b/packages/nc-gui/components/smartsheet/header/Menu.vue
index 7da72bdf27..7643370472 100644
--- a/packages/nc-gui/components/smartsheet/header/Menu.vue
+++ b/packages/nc-gui/components/smartsheet/header/Menu.vue
@@ -45,8 +45,21 @@ const { fieldsToGroupBy, groupByLimit } = useViewGroupByOrThrow(view)
const { isUIAllowed, isMetaReadOnly, isDataReadOnly } = useRoles()
+const { aiIntegrations } = useNocoAi()
+
const isLoading = ref<'' | 'hideOrShow' | 'setDisplay'>('')
+const columnInvalid = computed<{ isInvalid: boolean; tooltip: string }>(() => {
+ if (!column?.value) {
+ return {
+ isInvalid: false,
+ tooltip: '',
+ }
+ }
+
+ return isColumnInvalid(column.value, aiIntegrations.value, isPublic.value || !isUIAllowed('dataEdit'))
+})
+
const setAsDisplayValue = async () => {
isLoading.value = 'setDisplay'
try {
@@ -415,6 +428,10 @@ const onClickCopyFieldUrl = async (field: ColumnType) => {
await copy(field.id!)
isFieldIdCopied.value = true
+
+ await ncDelay(5000)
+
+ isFieldIdCopied.value = false
}
const onDeleteColumn = () => {
@@ -431,7 +448,7 @@ const onDeleteColumn = () => {
overlay-class-name="nc-dropdown-column-operations !border-1 rounded-lg !shadow-xl "
@click.stop="openDropdown"
>
-
+
@@ -441,14 +458,10 @@ const onDeleteColumn = () => {
-
+
- {{ $t('msg.invalidColumnConfiguration') }}
+ {{ $t(columnInvalid.tooltip) }}
{
const columnOrder = ref | null>(null)
const columnTypeName = computed(() => {
- if (column.value.uidt === UITypes.LongText && parseProp(column?.value?.meta)?.richMode) {
- return UITypesName.RichText
- }
if (column.value.uidt === UITypes.LinkToAnotherRecord && column.value.colOptions?.type === RelationTypes.ONE_TO_ONE) {
return UITypesName[UITypes.Links]
}
+ if (isAiButton(column.value)) {
+ return UITypesName.AIButton
+ }
+
return column.value.uidt ? UITypesName[column.value.uidt] : ''
})
diff --git a/packages/nc-gui/components/smartsheet/toolbar/ViewActionMenu.vue b/packages/nc-gui/components/smartsheet/toolbar/ViewActionMenu.vue
index f11c91ab0f..02da9d086d 100644
--- a/packages/nc-gui/components/smartsheet/toolbar/ViewActionMenu.vue
+++ b/packages/nc-gui/components/smartsheet/toolbar/ViewActionMenu.vue
@@ -152,6 +152,10 @@ const { copy } = useCopy()
const onViewIdCopy = async () => {
await copy(view.value!.id!)
isViewIdCopied.value = true
+
+ await ncDelay(5000)
+
+ isViewIdCopied.value = false
}
const onDelete = async () => {
diff --git a/packages/nc-gui/components/virtual-cell/Button.vue b/packages/nc-gui/components/virtual-cell/Button.vue
index d0fe37c7fa..72fe63ee28 100644
--- a/packages/nc-gui/components/virtual-cell/Button.vue
+++ b/packages/nc-gui/components/virtual-cell/Button.vue
@@ -210,7 +210,7 @@ const componentProps = computed(() => {