diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index f54fe1975a..8a7cb36d56 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -10,6 +10,7 @@ on: - "packages/nc-gui/**" - "packages/nocodb/**" - ".github/workflows/ci-cd.yml" + - "tests/playwright/**" pull_request: types: [opened, reopened, synchronize, ready_for_review, labeled] branches: [develop] diff --git a/.github/workflows/playwright-test-workflow.yml b/.github/workflows/playwright-test-workflow.yml index c081910a21..b3b0026d62 100644 --- a/.github/workflows/playwright-test-workflow.yml +++ b/.github/workflows/playwright-test-workflow.yml @@ -98,6 +98,14 @@ jobs: working-directory: ./tests/playwright run: E2E_DB_TYPE=${{ inputs.db }} npm run ci:test:shard:${{ inputs.shard }} + # Stress test added/modified tests + - name: Fetch develop branch + working-directory: ./tests/playwright + run: git fetch origin develop + - name: Stress test + working-directory: ./tests/playwright + run: E2E_DB_TYPE=${{ inputs.db }} node ./scripts/stressTestNewlyAddedTest.js + # Quick tests (pg on sqlite shard 0 and sqlite on sqlite shard 1) - name: Run quick server and tests (pg) if: ${{ inputs.db == 'sqlite' && inputs.shard == '1' }} @@ -132,13 +140,19 @@ jobs: name: playwright-report-quick-${{ inputs.shard }} path: ./tests/playwright/playwright-report-quick/ retention-days: 2 - + - uses: actions/upload-artifact@v3 if: always() with: name: playwright-report-${{ inputs.db }}-${{ inputs.shard }} path: ./tests/playwright/playwright-report/ retention-days: 2 + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report-stress-${{ inputs.db }}-${{ inputs.shard }} + path: ./tests/playwright/playwright-report-stress/ + retention-days: 2 - uses: actions/upload-artifact@v3 if: always() with: diff --git a/packages/nc-gui/app.vue b/packages/nc-gui/app.vue index b9bcde10f4..32480b0839 100644 --- a/packages/nc-gui/app.vue +++ b/packages/nc-gui/app.vue @@ -1,5 +1,5 @@ diff --git a/packages/nc-gui/components/cell/DateTimePicker.vue b/packages/nc-gui/components/cell/DateTimePicker.vue index d9cb6e2dea..8819d23ce7 100644 --- a/packages/nc-gui/components/cell/DateTimePicker.vue +++ b/packages/nc-gui/components/cell/DateTimePicker.vue @@ -1,6 +1,15 @@ 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 a6bf5b047d..555790359d 100644 --- a/packages/nc-gui/components/cell/Duration.vue +++ b/packages/nc-gui/components/cell/Duration.vue @@ -90,6 +90,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/Json.vue b/packages/nc-gui/components/cell/Json.vue index e21ce6d9df..f89ddf87aa 100644 --- a/packages/nc-gui/components/cell/Json.vue +++ b/packages/nc-gui/components/cell/Json.vue @@ -1,5 +1,17 @@ diff --git a/packages/nc-gui/components/cell/SingleSelect.vue b/packages/nc-gui/components/cell/SingleSelect.vue index 62e89fae6e..733abe34c0 100644 --- a/packages/nc-gui/components/cell/SingleSelect.vue +++ b/packages/nc-gui/components/cell/SingleSelect.vue @@ -108,7 +108,7 @@ useSelectedCellKeyupListener(active, (e) => { break default: // toggle only if char key pressed - if (e.key?.length === 1) { + if (!(e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) && e.key?.length === 1) { e.stopPropagation() isOpen.value = true } @@ -155,7 +155,7 @@ async function addIfMissingAndSave() { ) vModel.value = newOptValue await getMeta(column.value.fk_model_id!, true) - } catch (e) { + } catch (e: any) { console.log(e) message.error(await extractSdkResponseErrorMsg(e)) } 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 /> ) { { if (e.key === 'Enter' && !isReadonly.value) { e.stopPropagation() - modalVisible.value = true + if (!modalVisible.value) { + modalVisible.value = true + } else { + // click Attach File button + ;(document.querySelector('.nc-attachment-modal.active .nc-attach-file') as HTMLDivElement)?.click() + } } }) diff --git a/packages/nc-gui/components/dashboard/TreeView.vue b/packages/nc-gui/components/dashboard/TreeView.vue index 0302a0f553..bf05399189 100644 --- a/packages/nc-gui/components/dashboard/TreeView.vue +++ b/packages/nc-gui/components/dashboard/TreeView.vue @@ -6,20 +6,23 @@ import GithubButton from 'vue-github-button' import type { VNodeRef } from '#imports' import { Empty, + TabType, computed, + isDrawerOrModalExist, + isMac, reactive, ref, resolveComponent, useDialog, useNuxtApp, useProject, + useRoute, useTable, useTabs, useToggle, useUIPermission, watchEffect, } from '#imports' -import { TabType } from '~/lib' import MdiView from '~icons/mdi/eye-circle-outline' import MdiTableLarge from '~icons/mdi/table-large' @@ -35,6 +38,8 @@ const { deleteTable } = useTable() const { isUIAllowed } = useUIPermission() +const route = useRoute() + const [searchActive, toggleSearchActive] = useToggle() let key = $ref(0) @@ -216,6 +221,33 @@ const onSearchCloseIconClick = () => { filterQuery = '' toggleSearchActive(false) } + +const isCreateTableAllowed = computed( + () => + isUIAllowed('table-create') && + route.name !== 'index' && + route.name !== 'index-index' && + route.name !== 'index-index-create' && + route.name !== 'index-index-create-external' && + route.name !== 'index-user-index', +) + +useEventListener(document, 'keydown', async (e: KeyboardEvent) => { + const cmdOrCtrl = isMac() ? e.metaKey : e.ctrlKey + if (e.altKey && !e.shiftKey && !cmdOrCtrl) { + switch (e.keyCode) { + case 84: { + // ALT + T + if (isCreateTableAllowed.value && !isDrawerOrModalExist()) { + // prevent the key `T` is inputted to table title input + e.preventDefault() + openTableCreateDialog() + } + break + } + } + } +})