Skip to content

Commit

Permalink
Merge pull request #7788 from nocodb/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] committed Mar 4, 2024
2 parents 9317244 + 6609596 commit 71af871
Show file tree
Hide file tree
Showing 90 changed files with 3,663 additions and 2,008 deletions.
47 changes: 5 additions & 42 deletions packages/nc-gui/app.vue
@@ -1,6 +1,5 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
import { extractSdkResponseErrorMsg } from './utils'
import ErrorBoundary from './components/nc/ErrorBoundary.vue'
import { applyNonSelectable, computed, isEeUI, isMac, useCommandPalette, useRouter, useTheme } from '#imports'
import type { CommandPaletteType } from '~/lib'
Expand Down Expand Up @@ -98,49 +97,18 @@ onMounted(() => {
refreshCommandPalette()
})
})
let errorCount = 0
const handleError = async (error, clearError) => {
console.error('UI ERROR', error.value)
// if error is api error, show toast message with error message
if (error.value?.response) {
message.warn(await extractSdkResponseErrorMsg(error.value))
} else {
// else show generic error message
message.warn('Something went wrong. Please reload the page if page is not functioning properly.')
}
clearError()
// if error count is more than 3 within 3 second, navigate to home
// since it's likely endless loop of errors due to some UI issue in certain page
errorCount++
if (errorCount > 3) {
router.push('/')
}
// reset error count after 1 second
setTimeout(() => {
errorCount = 0
}, 3000)
}
</script>

<template>
<a-config-provider>
<NuxtLayout :name="disableBaseLayout ? false : 'base'">
<NuxtErrorBoundary>
<ErrorBoundary>
<NuxtPage :key="key" :transition="false" />

<!-- on error, clear error and show toast message -->
<template #error="{ error, clearError }">
{{ handleError(error, clearError) }}
</template>
</NuxtErrorBoundary>
</ErrorBoundary>
</NuxtLayout>
</a-config-provider>

<NuxtErrorBoundary>
<ErrorBoundary>
<div>
<!-- Command Menu -->
<CmdK
Expand All @@ -158,10 +126,5 @@ const handleError = async (error, clearError) => {
<!-- Documentation. Integrated NocoDB Docs directly inside the Product -->
<CmdJ />
</div>

<!-- on error, clear error and show toast message -->
<template #error="{ error, clearError }">
{{ handleError(error, clearError) }}
</template>
</NuxtErrorBoundary>
</ErrorBoundary>
</template>
10 changes: 7 additions & 3 deletions packages/nc-gui/assets/nc-icons/link.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
147 changes: 118 additions & 29 deletions packages/nc-gui/components/cell/RichText.vue
Expand Up @@ -6,6 +6,7 @@ import TurndownService from 'turndown'
import { marked } from 'marked'
import { generateJSON } from '@tiptap/html'
import Underline from '@tiptap/extension-underline'
import Placeholder from '@tiptap/extension-placeholder'
import { TaskItem } from '@/helpers/dbTiptapExtensions/task-item'
import { Link } from '@/helpers/dbTiptapExtensions/links'
import { IsExpandedFormOpenInj, IsFormInj, ReadonlyInj, RowHeightInj } from '#imports'
Expand All @@ -16,6 +17,10 @@ const props = defineProps<{
syncValueChange?: boolean
showMenu?: boolean
fullMode?: boolean
isFormField?: boolean
autofocus?: boolean
placeholder?: string
renderAsText?: boolean
}>()
const emits = defineEmits(['update:value'])
Expand All @@ -28,6 +33,8 @@ const readOnlyCell = inject(ReadonlyInj, ref(false))
const isForm = inject(IsFormInj, ref(false))
const isFocused = ref(false)
const turndownService = new TurndownService({})
turndownService.addRule('lineBreak', {
Expand Down Expand Up @@ -105,13 +112,19 @@ const editorDom = ref<HTMLElement | null>(null)
const vModel = useVModel(props, 'value', emits, { defaultValue: '' })
const tiptapExtensions = [
StarterKit,
StarterKit.configure({
heading: props.isFormField ? false : undefined,
}),
TaskList,
TaskItem.configure({
nested: true,
}),
Underline,
Link,
Placeholder.configure({
emptyEditorClass: 'is-editor-empty',
placeholder: props.placeholder,
}),
]
const editor = useEditor({
Expand All @@ -121,9 +134,18 @@ const editor = useEditor({
.turndown(editor.getHTML().replaceAll(/<p><\/p>/g, '<br />'))
.replaceAll(/\n\n<br \/>\n\n/g, '<br>\n\n')
vModel.value = markdown
vModel.value = props.isFormField && markdown === '<br />' ? '' : markdown
},
editable: !props.readOnly,
autofocus: props.autofocus,
onFocus: () => {
isFocused.value = true
},
onBlur: (e) => {
if (!(e?.event?.relatedTarget as HTMLElement)?.closest('.bubble-menu, .nc-textarea-rich-editor')) {
isFocused.value = false
}
},
})
const setEditorContent = (contentMd: any, focusEndOfDoc?: boolean) => {
Expand Down Expand Up @@ -153,21 +175,43 @@ const setEditorContent = (contentMd: any, focusEndOfDoc?: boolean) => {
}
if (props.syncValueChange) {
watch(vModel, () => {
watch([vModel, editor], () => {
setEditorContent(vModel.value)
})
}
if (props.isFormField) {
watch([props, editor], () => {
if (props.readOnly) {
editor.value?.setEditable(false)
} else {
editor.value?.setEditable(true)
}
})
}
watch(editorDom, () => {
if (!editorDom.value) return
setEditorContent(vModel.value, true)
if (props.isFormField) return
// Focus editor after editor is mounted
setTimeout(() => {
editor.value?.chain().focus().run()
}, 50)
})
useEventListener(
editorDom,
'focusout',
(e: FocusEvent) => {
if (!(e?.relatedTarget as HTMLElement)?.closest('.bubble-menu, .nc-textarea-rich-editor')) {
isFocused.value = false
}
},
true,
)
</script>

<template>
Expand All @@ -177,34 +221,51 @@ watch(editorDom, () => {
'flex flex-col flex-grow nc-rich-text-full': fullMode,
'nc-rich-text-embed flex flex-col pl-1 w-full': !fullMode,
'readonly': readOnly,
'nc-form-rich-text-field !p-0': isFormField,
}"
:tabindex="readOnlyCell ? -1 : 0"
:tabindex="readOnlyCell || isFormField ? -1 : 0"
>
<div
v-if="showMenu && !readOnly"
class="absolute top-0 right-0.5 xs:hidden"
:class="{
'max-w-[calc(100%_-_198px)] flex justify-end rounded-tr-2xl overflow-hidden': fullMode,
}"
>
<div class="nc-longtext-scrollbar">
<CellRichTextSelectedBubbleMenu v-if="editor" :editor="editor" embed-mode />
</div>
<div v-if="renderAsText" class="truncate">
<span v-if="editor"> {{ editor?.getText() ?? '' }}</span>
</div>
<CellRichTextSelectedBubbleMenuPopup v-if="editor" :editor="editor" />
<CellRichTextLinkOptions v-if="editor" :editor="editor" />
<EditorContent
ref="editorDom"
:editor="editor"
class="flex flex-col nc-textarea-rich-editor w-full"
:class="{
'mt-2.5 flex-grow': fullMode,
'nc-scrollbar-md': !fullMode || (!fullMode && isExpandedFormOpen),
'flex-grow': isExpandedFormOpen,
[`!overflow-hidden children:line-clamp-${rowHeight}`]:
!fullMode && readOnly && rowHeight && !isExpandedFormOpen && !isForm,
}"
/>
<template v-else>
<div
v-if="showMenu && !readOnly && !isFormField"
class="absolute top-0 right-0.5 xs:hidden"
:class="{
'max-w-[calc(100%_-_198px)] flex justify-end rounded-tr-2xl overflow-hidden': fullMode,
}"
>
<div class="nc-longtext-scrollbar">
<CellRichTextSelectedBubbleMenu v-if="editor" :editor="editor" embed-mode :is-form-field="isFormField" />
</div>
</div>
<CellRichTextSelectedBubbleMenuPopup v-if="editor && !isFormField" :editor="editor" />
<CellRichTextLinkOptions v-if="editor" :editor="editor" />
<EditorContent
ref="editorDom"
:editor="editor"
class="flex flex-col nc-textarea-rich-editor w-full"
:class="{
'mt-2.5 flex-grow': fullMode,
'nc-scrollbar-md': !fullMode || (!fullMode && isExpandedFormOpen),
'flex-grow': isExpandedFormOpen,
[`!overflow-hidden children:line-clamp-${rowHeight}`]:
!fullMode && readOnly && rowHeight && !isExpandedFormOpen && !isForm,
}"
/>
<div v-if="isFormField && !readOnly">
<div
class="overflow-hidden"
:class="isFocused ? 'max-h-[50px]' : 'max-h-0'"
:style="{
transition: 'max-height 0.2s ease-in-out',
}"
>
<CellRichTextSelectedBubbleMenu v-if="editor" :editor="editor" embed-mode is-form-field />
</div>
</div>
</template>
</div>
</template>

Expand All @@ -223,7 +284,28 @@ watch(editorDom, () => {
.nc-rich-text-embed {
.ProseMirror {
@apply !border-transparent max-h-full;
min-height: 8rem;
}
&:not(.nc-form-rich-text-field) {
.ProseMirror {
min-height: 8rem;
}
}
&.nc-form-rich-text-field {
.ProseMirror {
padding: 0;
}
&.readonly {
ul[data-type='taskList'] li input[type='checkbox'] {
background-color: #d5d5d9 !important;
&:not(:checked) {
@apply !border-gray-400;
}
&:focus {
box-shadow: none !important;
background-color: #d5d5d9 !important;
}
}
}
}
&.readonly {
.nc-textarea-rich-editor {
Expand Down Expand Up @@ -256,6 +338,13 @@ watch(editorDom, () => {
}

.nc-textarea-rich-editor {
.tiptap p.is-editor-empty:first-child::before {
color: #6a7184;
content: attr(data-placeholder);
float: left;
height: 0;
pointer-events: none;
}
.ProseMirror {
@apply flex-grow pt-1 border-1 border-gray-200 rounded-lg;

Expand Down

0 comments on commit 71af871

Please sign in to comment.