diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 388cb7c8a6..adfbbc756f 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -45,6 +45,8 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 + - name: remove use-node-version from .npmrc + run: sed -i '/^use-node-version/d' .npmrc - name: Get pnpm store directory shell: bash run: | @@ -78,6 +80,8 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 + - name: remove use-node-version from .npmrc + run: sed -i '/^use-node-version/d' .npmrc - name: Get pnpm store directory shell: bash run: | diff --git a/.github/workflows/playwright-test-workflow.yml b/.github/workflows/playwright-test-workflow.yml index f753fec7f8..fbe739b217 100644 --- a/.github/workflows/playwright-test-workflow.yml +++ b/.github/workflows/playwright-test-workflow.yml @@ -18,31 +18,21 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 - - name: Check node,pnpm Installation and set Path - shell: bash - working-directory: scripts/self-hosted-gh-runner - timeout-minutes: 1 - run: | - ./node-pnpm-check.sh - echo "make sure below mentioned versions are expected versions" - echo "If you are expecting the node and pnpm versions to be updated. Please update the node-pnpm-check.sh script" - env + - name: remove use-node-version from .npmrc + run: sed -i '/^use-node-version/d' .npmrc - name: Setup Node - if: ${{ env.SETUP_NODE != 'false' }} uses: actions/setup-node@v3 with: - node-version: ${{ env.NC_REQ_NODE_V }} + node-version: 18.14.0 - name: Setup pnpm - if: ${{ env.SETUP_PNPM != 'false' }} uses: pnpm/action-setup@v2 with: - version: ${{ env.NC_REQ_PNPM_V }} + version: 8 - name: Get pnpm store directory shell: bash run: | echo "STORE_PATH=/root/setup-pnpm/node_modules/.bin/store/v3" >> $GITHUB_ENV - uses: actions/cache@v3 - if: env.IS_NPM_CACHE_DOWNLOAD_REQUIRED == 'true' name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} diff --git a/.github/workflows/pre-build-for-playwright.yml b/.github/workflows/pre-build-for-playwright.yml index 079137dfff..59b4a81ce8 100644 --- a/.github/workflows/pre-build-for-playwright.yml +++ b/.github/workflows/pre-build-for-playwright.yml @@ -2,13 +2,7 @@ name: pre-build-for-playwright on: workflow_call: - inputs: - FORCE_RUN_PRERQUISITE_STEPS: - description: 'FORCE_RUN_PRERQUISITE_STEPS' - required: false - type: string - default: 'false' - + jobs: playwright: runs-on: [self-hosted, v3] @@ -16,31 +10,21 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 - - name: Check node,pnpm Installation and set Path - shell: bash - working-directory: scripts/self-hosted-gh-runner - timeout-minutes: 1 - run: | - ./node-pnpm-check.sh - echo "make sure below mentioned versions are expected versions" - echo "If you are expecting the node and pnpm versions to be updated. Please update the node-pnpm-check.sh script" - env - name: Setup Node - if: ${{ env.SETUP_NODE != 'false' }} uses: actions/setup-node@v3 with: - node-version: ${{ env.NC_REQ_NODE_V }} + node-version: 18.14.0 - name: Setup pnpm - if: ${{ env.SETUP_PNPM != 'false' }} uses: pnpm/action-setup@v2 with: - version: ${{ env.NC_REQ_PNPM_V }} + version: 8 + - name: remove use-node-version from .npmrc + run: sed -i '/^use-node-version/d' .npmrc - name: Get pnpm store directory shell: bash run: | echo "STORE_PATH=/root/setup-pnpm/node_modules/.bin/store/v3" >> $GITHUB_ENV - uses: actions/cache@v3 - if: env.IS_NPM_CACHE_DOWNLOAD_REQUIRED == 'true' name: Setup pnpm cache with: path: ${{ env.STORE_PATH }} diff --git a/.github/workflows/release-executables.yml b/.github/workflows/release-executables.yml index e98c0eb2b9..7b85111c5b 100644 --- a/.github/workflows/release-executables.yml +++ b/.github/workflows/release-executables.yml @@ -25,6 +25,7 @@ jobs: - name: Get pnpm store directory shell: bash run: | + sed -i '/^use-node-version/d' .npmrc echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - uses: actions/cache@v3 name: Setup pnpm cache diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 369ad4c629..00498b7928 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -34,6 +34,8 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: 'pnpm' + - name: remove use-node-version from .npmrc + run: sed -i '/^use-node-version/d' .npmrc - name: install dependencies run: pnpm bootstrap - name: run unit tests diff --git a/.github/workflows/update-sdk-path.yml b/.github/workflows/update-sdk-path.yml index 4ac8edb0a1..44d0519a6f 100644 --- a/.github/workflows/update-sdk-path.yml +++ b/.github/workflows/update-sdk-path.yml @@ -20,9 +20,9 @@ jobs: - name: Checkout uses: actions/checkout@v3 with: - fetch-depth: 0 - + fetch-depth: 0 - run: | + sed -i '/^use-node-version/d' .npmrc pnpm bootstrap - name: Create Pull Request diff --git a/README.md b/README.md index 6ac3a9a388..fbeab2db7d 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart spreadshe Documentation

-![All Views](https://user-images.githubusercontent.com/35857179/194825053-3aa3373d-3e0f-4b42-b3f1-42928332054a.gif) +![video avi](https://github.com/nocodb/nocodb/assets/86527202/e2fad786-f211-4dcb-9bd3-aaece83a6783)
@@ -106,6 +106,8 @@ nocodb/nocodb:latest > If you plan to input some special characters, you may need to change the character set and collation yourself when creating the database. Please check out the examples for [MySQL Docker](https://github.com/nocodb/nocodb/issues/1340#issuecomment-1049481043). +> Different commands just indicate the database that NocoDB will use internally for metadata storage, but that doesn't influence the ability to connect to a different database type. + ## Binaries ##### MacOS (x64) @@ -305,4 +307,4 @@ Thank you for your contributions! We appreciate all the contributions from the c - \ No newline at end of file + diff --git a/packages/nc-gui/assets/nc-icons/check.svg b/packages/nc-gui/assets/nc-icons/check.svg index 314287cb8e..21d49df996 100644 --- a/packages/nc-gui/assets/nc-icons/check.svg +++ b/packages/nc-gui/assets/nc-icons/check.svg @@ -1,5 +1,5 @@ - + diff --git a/packages/nc-gui/assets/nc-icons/file-image.svg b/packages/nc-gui/assets/nc-icons/file-image.svg new file mode 100644 index 0000000000..a0d907df5e --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/file-image.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/nc-gui/assets/nc-icons/lock.svg b/packages/nc-gui/assets/nc-icons/lock.svg index 45946a1cf5..05f258b22a 100644 --- a/packages/nc-gui/assets/nc-icons/lock.svg +++ b/packages/nc-gui/assets/nc-icons/lock.svg @@ -1,4 +1,4 @@ - - + + diff --git a/packages/nc-gui/assets/nc-icons/sort.svg b/packages/nc-gui/assets/nc-icons/sort.svg index 9acb6113c7..513c55c68b 100644 --- a/packages/nc-gui/assets/nc-icons/sort.svg +++ b/packages/nc-gui/assets/nc-icons/sort.svg @@ -1,5 +1,5 @@ - - - + + + diff --git a/packages/nc-gui/assets/style.scss b/packages/nc-gui/assets/style.scss index c317f29f0c..7d9c703132 100644 --- a/packages/nc-gui/assets/style.scss +++ b/packages/nc-gui/assets/style.scss @@ -2,6 +2,10 @@ @import '@vue-flow/core/dist/style.css'; @import '@vue-flow/core/dist/theme-default.css'; +html { + overflow: hidden; +} + body { line-height: 1.3125rem; } @@ -54,7 +58,7 @@ main { } .mobile { - .nc-scrollbar-md, nc-scrollbar-dark-md, nc-scrollbar-dark-md, nc-scrollbar-sm-dark, nc-scrollbar-x-md { + .nc-scrollbar-md, .nc-scrollbar-x-md, .nc-scrollbar-dark-md, .nc-scrollbar-x-md-dark, .nc-scrollbar-x-lg { &::-webkit-scrollbar { width: 0px; } @@ -64,6 +68,7 @@ main { .nc-scrollbar-md { overflow-y: scroll; overflow-x: hidden; + scrollbar-width: thin !important; &::-webkit-scrollbar { width: 4px; @@ -77,16 +82,46 @@ main { } &::-webkit-scrollbar-thumb { width: 4px; + @apply bg-gray-200; + } + &::-webkit-scrollbar-thumb:hover { @apply bg-gray-300; } +} + +.nc-scrollbar-x-md { + overflow-x: scroll; + scrollbar-width: thin !important; + + + &::-webkit-scrollbar { + width: 4px; + height: 4px; + } + &::-webkit-scrollbar-track-piece { + width: 0px; + } + &::-webkit-scrollbar { + @apply bg-transparent; + } + &::-webkit-scrollbar-thumb { + -webkit-border-radius: 10px; + border-radius: 10px; + + + width: 4px; + @apply bg-gray-200; + } &::-webkit-scrollbar-thumb:hover { - @apply bg-gray-400; + @apply bg-gray-300; } } .nc-scrollbar-dark-md { overflow-y: scroll; overflow-x: hidden; + scrollbar-width: thin !important; + &::-webkit-scrollbar { width: 4px; @@ -115,13 +150,14 @@ main { } } -.nc-scrollbar-sm-dark { - overflow-y: scroll; - overflow-x: hidden; +.nc-scrollbar-x-md-dark { + overflow-x: scroll; + scrollbar-width: thin !important; + &::-webkit-scrollbar { - width: 2px; - height: 2px; + width: 4px; + height: 4px; } &::-webkit-scrollbar-track-piece { width: 0px; @@ -130,20 +166,26 @@ main { @apply bg-transparent; } &::-webkit-scrollbar-thumb { + -webkit-border-radius: 10px; + border-radius: 10px; + + width: 4px; - @apply bg-gray-300; + background-color: rgba(0, 0, 0, 0.3) + } &::-webkit-scrollbar-thumb:hover { - @apply bg-gray-400; + background-color: rgba(0, 0, 0, 0.4) + } } -.nc-scrollbar-x-md { +.nc-scrollbar-x-lg { overflow-x: scroll; &::-webkit-scrollbar { - width: 4px; - height: 4px; + width: 8px; + height: 8px; } &::-webkit-scrollbar-track-piece { width: 0px; @@ -152,7 +194,11 @@ main { @apply bg-transparent; } &::-webkit-scrollbar-thumb { - width: 4px; + -webkit-border-radius: 10px; + border-radius: 10px; + + + width: 8px; @apply bg-gray-200; } &::-webkit-scrollbar-thumb:hover { @@ -160,10 +206,6 @@ main { } } -html { - overflow-y: auto !important; -} - main { @apply flex-0 w-full relative scrollbar-thin-dull; overflow-x: hidden; @@ -194,7 +236,7 @@ a { } .nc-base-menu-item { - @apply cursor-pointer flex items-center gap-2 py-2 after:(content-[''] absolute top-0 left-0 bottom-0 right-0 w-full h-full bg-current opacity-0 transition transition-opacity duration-100) hover:(after:(opacity-5)); + @apply cursor-pointer flex items-center gap-2 py-2; // &:hover { // .nc-icon { @@ -437,6 +479,9 @@ a { .nc-toolbar-btn { @apply !shadow-none rounded hover:(ring-1 ring-gray-200 ring-opacity-100 bg-gray-100 !text-gray-800) focus:(ring-1 ring-gray-300 ring-opacity-100 !text-gray-800 bg-gray-100) text-gray-600 text-xs font-medium px-2 border-0; } +.nc-toolbar-btn[disabled] { + @apply !text-gray-400 !cursor-not-allowed !hover:ring-0; +} .nc-warning-info { @apply !shadow-none rounded ring-1 ring-red-600; @@ -633,3 +678,7 @@ input[type='number'] { @apply xs:(visible opacity-100 !text-gray-500) } } + +.ant-message-notice-content { + @apply !rounded-md; +} \ No newline at end of file diff --git a/packages/nc-gui/components/account/License.vue b/packages/nc-gui/components/account/License.vue index e4d780bc17..cfd1f684b4 100644 --- a/packages/nc-gui/components/account/License.vue +++ b/packages/nc-gui/components/account/License.vue @@ -1,5 +1,5 @@ diff --git a/packages/nc-gui/components/cell/Json.vue b/packages/nc-gui/components/cell/Json.vue index 18326296f9..b4eaf90dac 100644 --- a/packages/nc-gui/components/cell/Json.vue +++ b/packages/nc-gui/components/cell/Json.vue @@ -72,13 +72,7 @@ const clear = () => { const formatJson = (json: string) => { try { - json = json - .trim() - .replace(/^\{\s*|\s*\}$/g, '') - .replace(/\n\s*/g, '') - json = `{${json}}` - - return json + return JSON.stringify(JSON.parse(json)) } catch (e) { console.log(e) return json diff --git a/packages/nc-gui/components/cell/MultiSelect.vue b/packages/nc-gui/components/cell/MultiSelect.vue index 7a64c35a1a..d8fe577a99 100644 --- a/packages/nc-gui/components/cell/MultiSelect.vue +++ b/packages/nc-gui/components/cell/MultiSelect.vue @@ -144,14 +144,14 @@ const selectedTitles = computed(() => } return 0 }) - : modelValue.split(',').map((el) => el.trim()) - : modelValue.map((el) => el.trim()) + : modelValue.split(',') + : modelValue : [], ) onMounted(() => { selectedIds.value = selectedTitles.value.flatMap((el) => { - const item = options.value.find((op) => op.title === el) + const item = options.value.find((op) => op.title === el || op.title === el?.trim()) const itemIdOrTitle = item?.id || item?.title if (itemIdOrTitle) { return [itemIdOrTitle] @@ -165,7 +165,7 @@ watch( () => modelValue, () => { selectedIds.value = selectedTitles.value.flatMap((el) => { - const item = options.value.find((op) => op.title === el) + const item = options.value.find((op) => op.title === el || op.title === el?.trim()) if (item && (item.id || item.title)) { return [(item.id || item.title)!] } diff --git a/packages/nc-gui/components/cell/Percent.vue b/packages/nc-gui/components/cell/Percent.vue index 55b6188e56..29c2efe3f9 100644 --- a/packages/nc-gui/components/cell/Percent.vue +++ b/packages/nc-gui/components/cell/Percent.vue @@ -49,8 +49,6 @@ const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value @keydown.right.stop @keydown.up.stop @keydown.delete.stop - @keydown.ctrl.z.stop - @keydown.meta.z.stop @selectstart.capture.stop @mousedown.stop /> diff --git a/packages/nc-gui/components/cell/PhoneNumber.vue b/packages/nc-gui/components/cell/PhoneNumber.vue index 24c3c8ef36..6a74c90caa 100644 --- a/packages/nc-gui/components/cell/PhoneNumber.vue +++ b/packages/nc-gui/components/cell/PhoneNumber.vue @@ -70,15 +70,19 @@ watch( @keydown.right.stop @keydown.up.stop @keydown.delete.stop - @keydown.ctrl.z.stop - @keydown.meta.z.stop @selectstart.capture.stop @mousedown.stop /> {{ $t('general.null') }} - + diff --git a/packages/nc-gui/components/cell/SingleSelect.vue b/packages/nc-gui/components/cell/SingleSelect.vue index 6d132cf0b0..0afc0e4c4b 100644 --- a/packages/nc-gui/components/cell/SingleSelect.vue +++ b/packages/nc-gui/components/cell/SingleSelect.vue @@ -104,7 +104,7 @@ const hasEditRoles = computed(() => isUIAllowed('dataEdit')) const editAllowed = computed(() => (hasEditRoles.value || isForm.value) && active.value) const vModel = computed({ - get: () => tempSelectedOptState.value ?? modelValue?.trim(), + get: () => tempSelectedOptState.value ?? modelValue, set: (val) => { if (val && isNewOptionCreateEnabled.value && (options.value ?? []).every((op) => op.title !== val)) { tempSelectedOptState.value = val @@ -259,7 +259,7 @@ const handleClose = (e: MouseEvent) => { useEventListener(document, 'click', handleClose, true) const selectedOpt = computed(() => { - return options.value.find((o) => o.value === vModel.value) + return options.value.find((o) => o.value === vModel.value || o.value === vModel.value?.trim()) }) diff --git a/packages/nc-gui/components/cell/Text.vue b/packages/nc-gui/components/cell/Text.vue index e3ec8698a6..2e4f6f2cde 100644 --- a/packages/nc-gui/components/cell/Text.vue +++ b/packages/nc-gui/components/cell/Text.vue @@ -43,8 +43,6 @@ const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value @keydown.right.stop @keydown.up.stop @keydown.delete.stop - @keydown.ctrl.z.stop - @keydown.meta.z.stop @selectstart.capture.stop @mousedown.stop /> diff --git a/packages/nc-gui/components/cell/TextArea.vue b/packages/nc-gui/components/cell/TextArea.vue index 6cf430bd22..90581d7e85 100644 --- a/packages/nc-gui/components/cell/TextArea.vue +++ b/packages/nc-gui/components/cell/TextArea.vue @@ -16,6 +16,7 @@ import { const props = defineProps<{ modelValue?: string | number isFocus?: boolean + virtual?: boolean }>() const emits = defineEmits(['update:modelValue']) @@ -65,6 +66,13 @@ onClickOutside(inputWrapperRef, (e) => { isVisible.value = false }) + +const onDblClick = () => { + if (!props.virtual) return + + isVisible.value = true + editEnabled.value = true +}