diff --git a/packages/nc-gui/assets/style.scss b/packages/nc-gui/assets/style.scss index 1a65ac5e13..87c00840fe 100644 --- a/packages/nc-gui/assets/style.scss +++ b/packages/nc-gui/assets/style.scss @@ -86,6 +86,11 @@ a { @apply relative after:(absolute top-[-2px] right-[-2px] w-[8px] h-[8px] rounded-full bg-primary content-[''] !z-20); } +// badge with count +.nc-count-badge { + @apply absolute flex items-center top-[-6px] right-[-6px] px-1 min-w-[14px] h-[14px] rounded-full bg-primary bg-opacity-100 text-white !text-[9px] !z-21; +} + // for highlighting toolbar menu item .nc-active-btn > .ant-btn { @apply bg-primary bg-opacity-20 hover:(bg-primary bg-opacity-20); diff --git a/packages/nc-gui/components.d.ts b/packages/nc-gui/components.d.ts index b94d48f043..1664e337f5 100644 --- a/packages/nc-gui/components.d.ts +++ b/packages/nc-gui/components.d.ts @@ -168,6 +168,7 @@ declare module '@vue/runtime-core' { MdiFileEyeOutline: typeof import('~icons/mdi/file-eye-outline')['default'] MdiFileImageBox: typeof import('~icons/mdi/file-image-box')['default'] MdiFilePlusOutline: typeof import('~icons/mdi/file-plus-outline')['default'] + MdiFileReplaceOutline: typeof import('~icons/mdi/file-replace-outline')['default'] MdiFileUploadOutline: typeof import('~icons/mdi/file-upload-outline')['default'] MdiFilterOutline: typeof import('~icons/mdi/filter-outline')['default'] MdiFlag: typeof import('~icons/mdi/flag')['default'] @@ -211,11 +212,15 @@ declare module '@vue/runtime-core' { MdiShieldKeyOutline: typeof import('~icons/mdi/shield-key-outline')['default'] MdiSlack: typeof import('~icons/mdi/slack')['default'] MdiSort: typeof import('~icons/mdi/sort')['default'] + MdiSortAscending: typeof import('~icons/mdi/sort-ascending')['default'] + MdiSortDescending: typeof import('~icons/mdi/sort-descending')['default'] MdiStar: typeof import('~icons/mdi/star')['default'] MdiStarOutline: typeof import('~icons/mdi/star-outline')['default'] MdiStorefrontOutline: typeof import('~icons/mdi/storefront-outline')['default'] MdiTable: typeof import('~icons/mdi/table')['default'] MdiTableArrowRight: typeof import('~icons/mdi/table-arrow-right')['default'] + MdiTableColumnPlusAfter: typeof import('~icons/mdi/table-column-plus-after')['default'] + MdiTableColumnPlusBefore: typeof import('~icons/mdi/table-column-plus-before')['default'] MdiTableLarge: typeof import('~icons/mdi/table-large')['default'] MdiText: typeof import('~icons/mdi/text')['default'] MdiThumbUp: typeof import('~icons/mdi/thumb-up')['default'] diff --git a/packages/nc-gui/components/account/SignupSettings.vue b/packages/nc-gui/components/account/SignupSettings.vue index 7311679a76..b9d2559d47 100644 --- a/packages/nc-gui/components/account/SignupSettings.vue +++ b/packages/nc-gui/components/account/SignupSettings.vue @@ -51,6 +51,6 @@ loadSettings() diff --git a/packages/nc-gui/components/cell/Currency.vue b/packages/nc-gui/components/cell/Currency.vue index da72a21fa9..c65a699d98 100644 --- a/packages/nc-gui/components/cell/Currency.vue +++ b/packages/nc-gui/components/cell/Currency.vue @@ -66,6 +66,8 @@ onMounted(() => { @keydown.right.stop @keydown.up.stop @keydown.delete.stop + @selectstart.capture.stop + @mousedown.stop /> {{ currency }} diff --git a/packages/nc-gui/components/cell/Decimal.vue b/packages/nc-gui/components/cell/Decimal.vue index 5591880433..5e7ed247e3 100644 --- a/packages/nc-gui/components/cell/Decimal.vue +++ b/packages/nc-gui/components/cell/Decimal.vue @@ -35,6 +35,8 @@ const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus() @keydown.right.stop @keydown.up.stop @keydown.delete.stop + @selectstart.capture.stop + @mousedown.stop /> {{ vModel }} diff --git a/packages/nc-gui/components/cell/Duration.vue b/packages/nc-gui/components/cell/Duration.vue index bcb32c34fc..e640754c38 100644 --- a/packages/nc-gui/components/cell/Duration.vue +++ b/packages/nc-gui/components/cell/Duration.vue @@ -89,6 +89,8 @@ const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus() @keydown.right.stop @keydown.up.stop @keydown.delete.stop + @selectstart.capture.stop + @mousedown.stop /> {{ localState }} diff --git a/packages/nc-gui/components/cell/Email.vue b/packages/nc-gui/components/cell/Email.vue index c5c20ced60..9d0de8ad18 100644 --- a/packages/nc-gui/components/cell/Email.vue +++ b/packages/nc-gui/components/cell/Email.vue @@ -35,6 +35,8 @@ const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus() @keydown.right.stop @keydown.up.stop @keydown.delete.stop + @selectstart.capture.stop + @mousedown.stop /> diff --git a/packages/nc-gui/components/cell/Float.vue b/packages/nc-gui/components/cell/Float.vue index a2a973d9b2..86c8a47cba 100644 --- a/packages/nc-gui/components/cell/Float.vue +++ b/packages/nc-gui/components/cell/Float.vue @@ -35,6 +35,8 @@ const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus() @keydown.right.stop @keydown.up.stop @keydown.delete.stop + @selectstart.capture.stop + @mousedown.stop /> {{ vModel }} diff --git a/packages/nc-gui/components/cell/Integer.vue b/packages/nc-gui/components/cell/Integer.vue index d62b871d8f..e9103ea54f 100644 --- a/packages/nc-gui/components/cell/Integer.vue +++ b/packages/nc-gui/components/cell/Integer.vue @@ -39,6 +39,8 @@ function onKeyDown(evt: KeyboardEvent) { @keydown.right.stop @keydown.up.stop @keydown.delete.stop + @selectstart.capture.stop + @mousedown.stop /> {{ vModel }} diff --git a/packages/nc-gui/components/cell/Percent.vue b/packages/nc-gui/components/cell/Percent.vue index 641f00890f..c8907656d2 100644 --- a/packages/nc-gui/components/cell/Percent.vue +++ b/packages/nc-gui/components/cell/Percent.vue @@ -33,6 +33,8 @@ const focus: VNodeRef = (el) => { @keydown.right.stop @keydown.up.stop @keydown.delete.stop + @selectstart.capture.stop + @mousedown.stop /> {{ vModel }} diff --git a/packages/nc-gui/components/cell/Text.vue b/packages/nc-gui/components/cell/Text.vue index 05745ead2c..ad85967e5e 100644 --- a/packages/nc-gui/components/cell/Text.vue +++ b/packages/nc-gui/components/cell/Text.vue @@ -34,6 +34,8 @@ const focus: VNodeRef = (el) => { @keydown.right.stop @keydown.up.stop @keydown.delete.stop + @selectstart.capture.stop + @mousedown.stop /> {{ vModel }} diff --git a/packages/nc-gui/components/cell/TextArea.vue b/packages/nc-gui/components/cell/TextArea.vue index 4ed873947f..f0280bf12e 100644 --- a/packages/nc-gui/components/cell/TextArea.vue +++ b/packages/nc-gui/components/cell/TextArea.vue @@ -31,6 +31,8 @@ const focus: VNodeRef = (el) => (el as HTMLTextAreaElement)?.focus() @keydown.right.stop @keydown.up.stop @keydown.delete.stop + @selectstart.capture.stop + @mousedown.stop /> {{ vModel }} diff --git a/packages/nc-gui/components/cell/Url.vue b/packages/nc-gui/components/cell/Url.vue index 9c8962465d..742ee0e661 100644 --- a/packages/nc-gui/components/cell/Url.vue +++ b/packages/nc-gui/components/cell/Url.vue @@ -84,6 +84,8 @@ watch( @keydown.right.stop @keydown.up.stop @keydown.delete.stop + @selectstart.capture.stop + @mousedown.stop /> []>([]) const logRef = ref() +const enableAbort = ref(false) + let socket: Socket | null +let socketInterval: NodeJS.Timer + const syncSource = ref({ id: '', type: 'Airtable', @@ -121,6 +125,7 @@ async function loadSyncSrc() { srcs[0].details = srcs[0].details || {} syncSource.value = migrateSync(srcs[0]) syncSource.value.details.syncSourceUrlOrId = srcs[0].details.shareId + socket?.emit('subscribe', syncSource.value.id) } else { syncSource.value = { id: '', @@ -146,7 +151,6 @@ async function loadSyncSrc() { } async function sync() { - step.value = 2 try { await $fetch(`/api/v1/db/meta/syncs/${syncSource.value.id}/trigger`, { baseURL, @@ -156,11 +160,36 @@ async function sync() { id: socket?.id, }, }) + socket?.emit('subscribe', syncSource.value.id) } catch (e: any) { message.error(await extractSdkResponseErrorMsg(e)) } } +async function abort() { + Modal.confirm({ + title: 'Are you sure you want to abort this job?', + type: 'warn', + content: + "This is a highly experimental feature and only marks job as not started, please don't abort the job unless you are sure job is stuck.", + onOk: async () => { + try { + await $fetch(`/api/v1/db/meta/syncs/${syncSource.value.id}/abort`, { + baseURL, + method: 'POST', + headers: { 'xc-auth': $state.token.value as string }, + params: { + id: socket?.id, + }, + }) + step.value = 1 + } catch (e: any) { + message.error(await extractSdkResponseErrorMsg(e)) + } + }, + }) +} + function migrateSync(src: any) { if (!src.details?.options) { src.details.options = { @@ -193,16 +222,6 @@ onMounted(async () => { extraHeaders: { 'xc-auth': $state.token.value as string }, }) - socket.on('connect_error', () => { - socket?.disconnect() - socket = null - }) - - // connect event does not provide data - socket.on('connect', () => { - console.log('socket connected') - }) - socket.on('progress', async (d: Record) => { progress.value.push(d) @@ -219,13 +238,46 @@ onMounted(async () => { } }) + socket.on('disconnect', () => { + console.log('socket disconnected') + const rcInterval = setInterval(() => { + if (socket?.connected) { + clearInterval(rcInterval) + socket?.emit('subscribe', syncSource.value.id) + } else { + socket?.connect() + } + }, 2000) + }) + + socket.on('job', () => { + step.value = 2 + }) + + // connect event does not provide data + socket.on('connect', () => { + console.log('socket connected') + if (syncSource.value.id) { + socket?.emit('subscribe', syncSource.value.id) + } + }) + + socket?.io.on('reconnect', () => { + console.log('socket reconnected') + if (syncSource.value.id) { + socket?.emit('subscribe', syncSource.value.id) + } + }) + await loadSyncSrc() }) onBeforeUnmount(() => { if (socket) { + socket.removeAllListeners() socket.disconnect() } + clearInterval(socketInterval) }) @@ -240,7 +292,7 @@ onBeforeUnmount(() => { >
-
{{ $t('title.quickImport') }} - AIRTABLE
+
{{ $t('title.quickImport') }} - AIRTABLE
@@ -382,6 +434,7 @@ onBeforeUnmount(() => { {{ $t('labels.goToDashboard') }} + ABORT
diff --git a/packages/nc-gui/components/smartsheet/Grid.vue b/packages/nc-gui/components/smartsheet/Grid.vue index fd694c7143..2eb66428c0 100644 --- a/packages/nc-gui/components/smartsheet/Grid.vue +++ b/packages/nc-gui/components/smartsheet/Grid.vue @@ -1,5 +1,5 @@