diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 0dbed85501..787bbe9cbf 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -63,6 +63,47 @@ jobs: - name: run unit tests working-directory: ./packages/nocodb run: npm run test:unit + unit-tests-pg: + runs-on: ubuntu-20.04 + timeout-minutes: 40 + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + steps: + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 16.15.0 + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Cache node modules + uses: actions/cache@v3 + env: + cache-name: cache-node-modules + + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + - name: setup pg + working-directory: ./ + run: docker-compose -f ./tests/playwright/scripts/docker-compose-playwright-pg.yml up -d & + - name: install dependencies nocodb-sdk + working-directory: ./packages/nocodb-sdk + run: npm install + - name: build nocodb-sdk + working-directory: ./packages/nocodb-sdk + run: npm run build:main + - name: Install dependencies + working-directory: ./packages/nocodb + run: npm install + - name: run unit tests + working-directory: ./packages/nocodb + run: npm run test:unit:pg playwright-mysql-1: if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} uses: ./.github/workflows/playwright-test-workflow.yml diff --git a/.github/workflows/publish-api-docs.yml b/.github/workflows/publish-api-docs.yml index e54cd12976..47860cdd7f 100644 --- a/.github/workflows/publish-api-docs.yml +++ b/.github/workflows/publish-api-docs.yml @@ -4,7 +4,7 @@ on: push: branches: [ master ] paths: - - "scripts/sdk/swagger.json" + - "packages/nocodb/src/schema/swagger.json" release: types: [ published ] @@ -22,7 +22,7 @@ jobs: env: API_TOKEN_GITHUB: ${{ secrets.GH_TOKEN }} with: - source_file: 'scripts/sdk/swagger.json' + source_file: 'packages/nocodb/src/schema/swagger.json' destination_repo: 'nocodb/noco-apis-doc' destination_folder: 'src' user_email: 'oof1lab@gmail.com' @@ -34,7 +34,7 @@ jobs: env: API_TOKEN_GITHUB: ${{ secrets.GH_TOKEN }} with: - source_file: 'scripts/sdk/swagger.json' + source_file: 'packages/nocodb/src/schema/swagger.json' destination_repo: 'nocodb/noco-apis-doc' destination_folder: 'meta-src' user_email: 'oof1lab@gmail.com' diff --git a/.github/workflows/release-timely-executables.yml b/.github/workflows/release-timely-executables.yml index ab7706709c..e3c18570ae 100644 --- a/.github/workflows/release-timely-executables.yml +++ b/.github/workflows/release-timely-executables.yml @@ -62,6 +62,10 @@ jobs: ./make.sh sudo cp ./ldid /usr/local/bin + - uses: actions/setup-node@v3 + with: + node-version: 16 + - name: Update nocodb-timely env: TAG: ${{ github.event.inputs.tag || inputs.tag }} @@ -75,11 +79,6 @@ jobs: git tag $TAG git push --tags - - - uses: actions/setup-node@v3 - with: - node-version: 16 - - name : Install dependencies and build executables run: | # install npm dependendencies diff --git a/charts/nocodb/templates/pvc.yaml b/charts/nocodb/templates/pvc.yaml index 67656c01d1..092a1b0439 100644 --- a/charts/nocodb/templates/pvc.yaml +++ b/charts/nocodb/templates/pvc.yaml @@ -5,10 +5,10 @@ metadata: labels: {{- include "nocodb.selectorLabels" . | nindent 8 }} spec: - accessModes: - - ReadWriteMany resources: requests: storage: {{ .Values.storage.size }} storageClassName: {{ .Values.storage.storageClassName }} + accessModes: + {{- default (toYaml .Values.storage.accessModes) "- ReadWriteMany" | nindent 4 }} volumeMode: Filesystem diff --git a/packages/nc-gui/assets/style.scss b/packages/nc-gui/assets/style.scss index 3cd427b4b9..25f17ff5e9 100644 --- a/packages/nc-gui/assets/style.scss +++ b/packages/nc-gui/assets/style.scss @@ -287,6 +287,10 @@ a { @apply !shadow-none rounded hover:(ring-1 ring-primary ring-opacity-100) focus:(ring-1 ring-accent ring-opacity-100); } +.nc-warning-info { + @apply !shadow-none rounded ring-1 ring-red-600 +} + .ant-modal { @apply !top-[50px]; } diff --git a/packages/nc-gui/components.d.ts b/packages/nc-gui/components.d.ts index 99bc5645f2..372758da9a 100644 --- a/packages/nc-gui/components.d.ts +++ b/packages/nc-gui/components.d.ts @@ -89,6 +89,7 @@ declare module '@vue/runtime-core' { IcTwotoneWidthNormal: typeof import('~icons/ic/twotone-width-normal')['default'] LogosGoogleGmail: typeof import('~icons/logos/google-gmail')['default'] LogosMysqlIcon: typeof import('~icons/logos/mysql-icon')['default'] + LogosOracle: typeof import('~icons/logos/oracle')['default'] LogosPostgresql: typeof import('~icons/logos/postgresql')['default'] LogosRedditIcon: typeof import('~icons/logos/reddit-icon')['default'] LogosSnowflakeIcon: typeof import('~icons/logos/snowflake-icon')['default'] @@ -203,6 +204,8 @@ declare module '@vue/runtime-core' { MdiLogin: typeof import('~icons/mdi/login')['default'] MdiLogout: typeof import('~icons/mdi/logout')['default'] MdiMagnify: typeof import('~icons/mdi/magnify')['default'] + MdiMapMarker: typeof import('~icons/mdi/map-marker')['default'] + MdiMapMarkerAlert: typeof import('~icons/mdi/map-marker-alert')['default'] MdiMenu: typeof import('~icons/mdi/menu')['default'] MdiMenuDown: typeof import('~icons/mdi/menu-down')['default'] MdiMicrosoftTeams: typeof import('~icons/mdi/microsoft-teams')['default'] @@ -249,8 +252,12 @@ declare module '@vue/runtime-core' { NcIconsRowHeightMedium: typeof import('~icons/nc-icons/row-height-medium')['default'] NcIconsRowHeightShort: typeof import('~icons/nc-icons/row-height-short')['default'] NcIconsRowHeightTall: typeof import('~icons/nc-icons/row-height-tall')['default'] + PhChatTextThin: typeof import('~icons/ph/chat-text-thin')['default'] PhCloudLightningDuotone: typeof import('~icons/ph/cloud-lightning-duotone')['default'] + PhCloudLightningThin: typeof import('~icons/ph/cloud-lightning-thin')['default'] PhFileCsv: typeof import('~icons/ph/file-csv')['default'] + PhUserPlusThin: typeof import('~icons/ph/user-plus-thin')['default'] + PhUsersThreeThin: typeof import('~icons/ph/users-three-thin')['default'] RiLineHeight: typeof import('~icons/ri/line-height')['default'] RiTeamFill: typeof import('~icons/ri/team-fill')['default'] RouterLink: typeof import('vue-router')['RouterLink'] diff --git a/packages/nc-gui/components/account/ResetPassword.vue b/packages/nc-gui/components/account/ResetPassword.vue index 804196f102..dc3d17fb55 100644 --- a/packages/nc-gui/components/account/ResetPassword.vue +++ b/packages/nc-gui/components/account/ResetPassword.vue @@ -54,7 +54,7 @@ const passwordChange = async () => { message.success(t('msg.success.passwordChanged')) - signOut() + await signOut() navigateTo('/signin') } diff --git a/packages/nc-gui/components/account/UserList.vue b/packages/nc-gui/components/account/UserList.vue index b1186e3481..281d04a85a 100644 --- a/packages/nc-gui/components/account/UserList.vue +++ b/packages/nc-gui/components/account/UserList.vue @@ -1,6 +1,6 @@ + + + + diff --git a/packages/nc-gui/components/cell/MultiSelect.vue b/packages/nc-gui/components/cell/MultiSelect.vue index 7bd77a36ef..9d6ec72434 100644 --- a/packages/nc-gui/components/cell/MultiSelect.vue +++ b/packages/nc-gui/components/cell/MultiSelect.vue @@ -32,6 +32,7 @@ interface Props { modelValue?: string | string[] rowIndex?: number disableOptionCreation?: boolean + location?: 'cell' | 'filter' } const { modelValue, disableOptionCreation } = defineProps() @@ -336,7 +337,7 @@ useEventListener(document, 'click', handleClose, true) v-for="op of options" :key="op.id || op.title" :value="op.title" - :data-testid="`select-option-${column.title}-${rowIndex}`" + :data-testid="`select-option-${column.title}-${location === 'filter' ? 'filter' : rowIndex}`" :class="`nc-select-option-${column.title}-${op.title}`" @click.stop > diff --git a/packages/nc-gui/components/cell/SingleSelect.vue b/packages/nc-gui/components/cell/SingleSelect.vue index 3bf447a7c6..dcdb5b3b28 100644 --- a/packages/nc-gui/components/cell/SingleSelect.vue +++ b/packages/nc-gui/components/cell/SingleSelect.vue @@ -19,6 +19,7 @@ import { isDrawerOrModalExist, ref, useEventListener, + useProject, useRoles, useSelectedCellKeyupListener, watch, @@ -247,12 +248,12 @@ useEventListener(document, 'click', handleClose, true) { NULL - + diff --git a/packages/nc-gui/components/cell/TextArea.vue b/packages/nc-gui/components/cell/TextArea.vue index 86d0564e2e..21ebfd8e0b 100644 --- a/packages/nc-gui/components/cell/TextArea.vue +++ b/packages/nc-gui/components/cell/TextArea.vue @@ -45,3 +45,9 @@ const focus: VNodeRef = (el) => (el as HTMLTextAreaElement)?.focus() {{ vModel }} + + diff --git a/packages/nc-gui/components/cell/attachment/utils.ts b/packages/nc-gui/components/cell/attachment/utils.ts index 438ae5c599..86e490a4fb 100644 --- a/packages/nc-gui/components/cell/attachment/utils.ts +++ b/packages/nc-gui/components/cell/attachment/utils.ts @@ -13,6 +13,7 @@ import { isImage, message, ref, + storeToRefs, useApi, useAttachment, useFileDialog, @@ -51,7 +52,7 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState( /** for image carousel */ const selectedImage = ref() - const { project } = useProject() + const { project } = storeToRefs(useProject()) const { api, isLoading } = useApi() diff --git a/packages/nc-gui/components/dashboard/TreeView.vue b/packages/nc-gui/components/dashboard/TreeView.vue index 2c028ad472..5b1d40e49e 100644 --- a/packages/nc-gui/components/dashboard/TreeView.vue +++ b/packages/nc-gui/components/dashboard/TreeView.vue @@ -17,6 +17,7 @@ import { reactive, ref, resolveComponent, + storeToRefs, useDialog, useGlobal, useNuxtApp, @@ -35,9 +36,12 @@ const { addTab, updateTab } = useTabs() const { $api, $e } = useNuxtApp() -const { bases, tables, loadTables, isSharedBase } = useProject() +const projectStore = useProject() -const { activeTab } = useTabs() +const { loadTables } = projectStore +const { bases, tables, isSharedBase } = storeToRefs(projectStore) + +const { activeTab } = storeToRefs(useTabs()) const { deleteTable } = useTable() diff --git a/packages/nc-gui/components/dashboard/settings/AppStore.vue b/packages/nc-gui/components/dashboard/settings/AppStore.vue index a957604c2b..14602061e0 100644 --- a/packages/nc-gui/components/dashboard/settings/AppStore.vue +++ b/packages/nc-gui/components/dashboard/settings/AppStore.vue @@ -20,7 +20,7 @@ const fetchPluginApps = async () => { apps = plugins.map((p) => ({ ...p, tags: p.tags ? p.tags.split(',') : [], - parsedInput: p.input && JSON.parse(p.input), + parsedInput: p.input && JSON.parse(p.input as string), })) } catch (e: any) { message.error(await extractSdkResponseErrorMsg(e)) diff --git a/packages/nc-gui/components/dashboard/settings/AuditTab.vue b/packages/nc-gui/components/dashboard/settings/AuditTab.vue index b5a4edef5a..b0319244d7 100644 --- a/packages/nc-gui/components/dashboard/settings/AuditTab.vue +++ b/packages/nc-gui/components/dashboard/settings/AuditTab.vue @@ -1,11 +1,11 @@ diff --git a/packages/nc-gui/components/general/ShortcutLabel.vue b/packages/nc-gui/components/general/ShortcutLabel.vue new file mode 100644 index 0000000000..2e861cd948 --- /dev/null +++ b/packages/nc-gui/components/general/ShortcutLabel.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/packages/nc-gui/components/shared-view/Map.vue b/packages/nc-gui/components/shared-view/Map.vue new file mode 100644 index 0000000000..ae2c69aa27 --- /dev/null +++ b/packages/nc-gui/components/shared-view/Map.vue @@ -0,0 +1,42 @@ + + + diff --git a/packages/nc-gui/components/smartsheet/ApiSnippet.vue b/packages/nc-gui/components/smartsheet/ApiSnippet.vue index 8a892c2748..192af6a237 100644 --- a/packages/nc-gui/components/smartsheet/ApiSnippet.vue +++ b/packages/nc-gui/components/smartsheet/ApiSnippet.vue @@ -6,6 +6,7 @@ import { inject, message, ref, + storeToRefs, useCopy, useGlobal, useI18n, @@ -24,7 +25,7 @@ const emits = defineEmits(['update:modelValue']) const { t } = useI18n() -const { project } = $(useProject()) +const { project } = $(storeToRefs(useProject())) const { appInfo, token } = $(useGlobal()) diff --git a/packages/nc-gui/components/smartsheet/Cell.vue b/packages/nc-gui/components/smartsheet/Cell.vue index 784cbaf1a0..5144f2d1cd 100644 --- a/packages/nc-gui/components/smartsheet/Cell.vue +++ b/packages/nc-gui/components/smartsheet/Cell.vue @@ -21,6 +21,7 @@ import { isDuration, isEmail, isFloat, + isGeoData, isInt, isJSON, isManualSaved, @@ -38,6 +39,7 @@ import { isYear, provide, ref, + storeToRefs, toRef, useDebounceFn, useProject, @@ -84,7 +86,7 @@ const isLocked = inject(IsLockedInj, ref(false)) const { currentRow } = useSmartsheetRowStoreOrThrow() -const { sqlUis } = useProject() +const { sqlUis } = storeToRefs(useProject()) const sqlUi = ref(column.value?.base_id ? sqlUis.value[column.value?.base_id] : Object.values(sqlUis.value)[0]) @@ -100,7 +102,9 @@ const syncValue = useDebounceFn( ) const vModel = computed({ - get: () => props.modelValue, + get: () => { + return props.modelValue + }, set: (val) => { if (val !== props.modelValue) { currentRow.value.rowMeta.changed = true @@ -136,6 +140,15 @@ const isNumericField = computed(() => { isDuration(column.value) ) }) + +// disable contexxtmenu event propagation when cell is in +// editable state and typable (e.g. text area) +// this is to prevent the custom grid view context menu from opening +const onContextmenu = (e: MouseEvent) => { + if (props.editEnabled && isTypableInputColumn(column.value)) { + e.stopPropagation() + } +}