diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index f54fe1975a..2b3c64550b 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] @@ -17,6 +18,7 @@ on: - "packages/nc-gui/**" - "packages/nocodb/**" - ".github/workflows/ci-cd.yml" + - "tests/playwright/**" concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -96,4 +98,4 @@ jobs: uses: ./.github/workflows/playwright-test-workflow.yml with: db: pg - shard: 2 \ No newline at end of file + shard: 2 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/package.json b/package.json index e6fb4a44bd..bd529ad8c2 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,9 @@ "doc": "lerna run doc", "install:local:dep": "cd packages/nc-lib-gui;npm uninstall -S xc-lib;rm package-lock.json; npm i ../../../xc-lib-private; cd ../xc-instant;npm uninstall -S xc-lib xc-lib-gui;npm i ../../../xc-lib-private;npm i ../xc-lib-gui", "install:npm:dep": "cd packages/nc-lib-gui;npm uninstall -S xc-lib; npm i -S xc-lib@latest; cd ../xc-instant;npm uninstall -S xc-lib xc-lib-gui;npm i -S xc-lib@latest xc-lib-gui@latest;npm i ../xc-lib-gui", - "prepare": "husky install" + "prepare": "husky install", + "start:pg": "docker-compose -f ./tests/playwright/scripts/docker-compose-pg.yml up -d", + "stop:pg": "docker-compose -f ./tests/playwright/scripts/docker-compose-pg.yml down" }, "dependencies": { "express": "^4.18.1", diff --git a/packages/nc-cli/package-lock.json b/packages/nc-cli/package-lock.json index 538e6fc841..7ab100f10c 100644 --- a/packages/nc-cli/package-lock.json +++ b/packages/nc-cli/package-lock.json @@ -9465,9 +9465,9 @@ } }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -22773,9 +22773,9 @@ "dev": true }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "requires": { "brace-expansion": "^1.1.7" } 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 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/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 0445193150..5258ffe327 100644 --- a/packages/nc-gui/components/cell/SingleSelect.vue +++ b/packages/nc-gui/components/cell/SingleSelect.vue @@ -106,7 +106,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 } @@ -153,7 +153,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..8a4f6a4523 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,34 @@ 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() + $e('c:shortcut', { key: 'ALT + T' }) + openTableCreateDialog() + } + break + } + } + } +})