Browse Source

Merge branch 'develop' into qr-prototyping-cleanedup

pr-4468-qr-code-extraction
Daniel Spaude 2 years ago
parent
commit
1b3344a518
No known key found for this signature in database
GPG Key ID: 654A3D1FA4F35FFE
  1. 5
      packages/nc-gui/assets/style.scss
  2. 1
      packages/nc-gui/components.d.ts
  3. 4
      packages/nc-gui/components/account/UserList.vue
  4. 4
      packages/nc-gui/components/account/UsersModal.vue
  5. 42
      packages/nc-gui/components/cell/MultiSelect.vue
  6. 34
      packages/nc-gui/components/cell/SingleSelect.vue
  7. 9
      packages/nc-gui/components/smartsheet/column/SelectOptions.vue
  8. 12
      packages/nc-gui/composables/useColumnCreateStore.ts
  9. 4
      packages/nc-gui/package-lock.json
  10. 1
      packages/nc-gui/pages/account/index.vue
  11. 2
      packages/nc-lib-gui/package.json
  12. 15
      packages/noco-docs/content/en/engineering/development-setup.md
  13. 4
      packages/noco-docs/content/en/engineering/repository-structure.md
  14. 3
      packages/noco-docs/content/en/engineering/testing.md
  15. 48
      packages/noco-docs/content/en/setup-and-usages/account-settings.md
  16. 13
      packages/noco-docs/content/en/setup-and-usages/app-store.md
  17. 8
      packages/noco-docs/content/en/setup-and-usages/audit.md
  18. 39
      packages/noco-docs/content/en/setup-and-usages/expanded-form.md
  19. 4
      packages/noco-docs/content/en/setup-and-usages/meta-management.md
  20. 9
      packages/noco-docs/content/en/setup-and-usages/table-operations.md
  21. 7
      packages/noco-docs/content/en/setup-and-usages/team-and-auth.md
  22. 2
      packages/noco-docs/content/en/setup-and-usages/views.md
  23. 4
      packages/nocodb-sdk/package-lock.json
  24. 2
      packages/nocodb-sdk/package.json
  25. 34
      packages/nocodb/package-lock.json
  26. 4
      packages/nocodb/package.json
  27. 2
      packages/nocodb/src/lib/db/sql-client/lib/KnexClient.ts
  28. 83
      packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts
  29. 4
      packages/nocodb/src/lib/db/sql-client/lib/pg/PgClient.ts
  30. 26
      packages/nocodb/src/lib/db/sql-data-mapper/lib/BaseModel.ts
  31. 17
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSql.ts
  32. 3
      packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts
  33. 4
      packages/nocodb/src/lib/meta/api/index.ts
  34. 4
      packages/nocodb/src/lib/meta/api/orgLicenseApis.ts
  35. 3
      packages/nocodb/src/lib/meta/api/publicApis/publicDataApis.ts
  36. 2
      packages/nocodb/src/lib/meta/api/swagger/swaggerApis.ts
  37. 12
      packages/nocodb/src/lib/meta/api/sync/helpers/job.ts
  38. 2
      packages/nocodb/src/lib/meta/api/testApis.ts
  39. 18
      packages/nocodb/src/lib/services/test/TestResetService/index.ts
  40. 10
      packages/nocodb/src/lib/utils/projectAcl.ts

5
packages/nc-gui/assets/style.scss

@ -281,3 +281,8 @@ a {
.ant-modal {
@apply !top-[50px];
}
.ant-select-item-option-active:not(.ant-select-item-option-disabled) {
@apply bg-primary bg-opacity-20;
}

1
packages/nc-gui/components.d.ts vendored

@ -125,7 +125,6 @@ declare module '@vue/runtime-core' {
MdiBugOutline: typeof import('~icons/mdi/bug-outline')['default']
MdiCalculator: typeof import('~icons/mdi/calculator')['default']
MdiCalendarMonth: typeof import('~icons/mdi/calendar-month')['default']
MdiCancel: typeof import('~icons/mdi/cancel')['default']
MdiCardsHeart: typeof import('~icons/mdi/cards-heart')['default']
MdiCellphoneMessage: typeof import('~icons/mdi/cellphone-message')['default']
MdiChat: typeof import('~icons/mdi/chat')['default']

4
packages/nc-gui/components/account/UserList.vue

@ -29,7 +29,9 @@ const searchText = ref<string>('')
const pagination = reactive({
total: 0,
pageSize: 10,
position: ['bottomCenter'],
})
const loadUsers = async (page = currentPage, limit = currentLimit) => {
currentPage = page
try {
@ -158,7 +160,7 @@ const copyPasswordResetUrl = async (user: User) => {
<a-table
:row-key="(record) => record.id"
:data-source="users"
:pagination="{ position: ['bottomCenter'] }"
:pagination="pagination"
:loading="isLoading"
size="small"
@change="loadUsers($event.current)"

4
packages/nc-gui/components/account/UsersModal.vue

@ -4,13 +4,13 @@ import {
Form,
computed,
extractSdkResponseErrorMsg,
isEmail,
message,
ref,
useCopy,
useDashboard,
useI18n,
useNuxtApp,
validateEmail,
} from '#imports'
import type { User } from '~/lib'
import { Role } from '~/lib'
@ -52,7 +52,7 @@ const validators = computed(() => {
callback('Email is required')
return
}
const invalidEmails = (value || '').split(/\s*,\s*/).filter((e: string) => !isEmail(e))
const invalidEmails = (value || '').split(/\s*,\s*/).filter((e: string) => !validateEmail(e))
if (invalidEmails.length > 0) {
callback(`${invalidEmails.length > 1 ? ' Invalid emails:' : 'Invalid email:'} ${invalidEmails.join(', ')} `)
} else {

42
packages/nc-gui/components/cell/MultiSelect.vue

@ -33,8 +33,6 @@ const { modelValue } = defineProps<Props>()
const emit = defineEmits(['update:modelValue'])
const { isMysql } = useProject()
const column = inject(ColumnInj)!
const readOnly = inject(ReadonlyInj)!
@ -59,6 +57,8 @@ const { $api } = useNuxtApp()
const { getMeta } = useMetas()
const { isPg, isMysql } = useProject()
// a variable to keep newly created options value
// temporary until it's add the option to column meta
const tempSelectedOptsState = reactive<string[]>([])
@ -171,8 +171,19 @@ useSelectedCellKeyupListener(active, (e) => {
isOpen.value = true
}
break
case 'ArrowUp':
case 'ArrowDown':
case 'ArrowRight':
case 'ArrowLeft':
case 'Delete':
// skip
break
default:
isOpen.value = true
// toggle only if char key pressed
if (e.key?.length === 1) {
e.stopPropagation()
isOpen.value = true
}
break
}
})
@ -195,9 +206,28 @@ async function addIfMissingAndSave() {
})
column.value.colOptions = { options: newOptions.map(({ value: _, ...rest }) => rest) }
await $api.dbTableColumn.update((column.value as { fk_column_id?: string })?.fk_column_id || (column.value?.id as string), {
...column.value,
})
const updatedColMeta = { ...column.value }
// todo: refactor and avoid repetition
if (updatedColMeta.cdf) {
// Postgres returns default value wrapped with single quotes & casted with type so we have to get value between single quotes to keep it unified for all databases
if (isPg.value) {
updatedColMeta.cdf = updatedColMeta.cdf.substring(
updatedColMeta.cdf.indexOf(`'`) + 1,
updatedColMeta.cdf.lastIndexOf(`'`),
)
}
// Mysql escapes single quotes with backslash so we keep quotes but others have to unescaped
if (!isMysql.value) {
updatedColMeta.cdf = updatedColMeta.cdf.replace(/''/g, "'")
}
}
await $api.dbTableColumn.update(
(column.value as { fk_column_id?: string })?.fk_column_id || (column.value?.id as string),
updatedColMeta,
)
activeOptCreateInProgress.value--
if (!activeOptCreateInProgress.value) {

34
packages/nc-gui/components/cell/SingleSelect.vue

@ -49,6 +49,8 @@ const searchVal = ref()
const { getMeta } = useMetas()
const { isPg, isMysql } = useProject()
// a variable to keep newly created option value
// temporary until it's add the option to column meta
const tempSelectedOptState = ref<string>()
@ -102,6 +104,13 @@ useSelectedCellKeyupListener(active, (e) => {
isOpen.value = true
}
break
default:
// toggle only if char key pressed
if (e.key?.length === 1) {
e.stopPropagation()
isOpen.value = true
}
break
}
})
@ -120,9 +129,28 @@ async function addIfMissingAndSave() {
})
column.value.colOptions = { options: options.value.map(({ value: _, ...rest }) => rest) }
await $api.dbTableColumn.update((column.value as { fk_column_id?: string })?.fk_column_id || (column.value?.id as string), {
...column.value,
})
const updatedColMeta = { ...column.value }
// todo: refactor and avoid repetition
if (updatedColMeta.cdf) {
// Postgres returns default value wrapped with single quotes & casted with type so we have to get value between single quotes to keep it unified for all databases
if (isPg.value) {
updatedColMeta.cdf = updatedColMeta.cdf.substring(
updatedColMeta.cdf.indexOf(`'`) + 1,
updatedColMeta.cdf.lastIndexOf(`'`),
)
}
// Mysql escapes single quotes with backslash so we keep quotes but others have to unescaped
if (!isMysql.value) {
updatedColMeta.cdf = updatedColMeta.cdf.replace(/''/g, "'")
}
}
await $api.dbTableColumn.update(
(column.value as { fk_column_id?: string })?.fk_column_id || (column.value?.id as string),
updatedColMeta,
)
vModel.value = newOptValue
await getMeta(column.value.fk_model_id!, true)
} catch (e) {

9
packages/nc-gui/components/smartsheet/column/SelectOptions.vue

@ -174,13 +174,12 @@ watch(inputs, () => {
/>
</div>
</template>
<template #footer>
<div v-if="validateInfos?.['colOptions.options']?.help?.[0]?.[0]" class="text-error text-[10px] my-2">
{{ validateInfos['colOptions.options'].help[0][0] }}
</div>
</template>
</Draggable>
</div>
<div v-if="validateInfos?.['colOptions.options']?.help?.[0]?.[0]" class="text-error text-[10px] mb-1 mt-2">
{{ validateInfos['colOptions.options'].help[0][0] }}
</div>
<a-button type="dashed" class="w-full caption mt-2" @click="addNewOption()">
<div class="flex items-center">
<MdiPlus />

12
packages/nc-gui/composables/useColumnCreateStore.ts

@ -195,9 +195,15 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState
try {
if (!(await validate())) return
} catch (e) {
console.log(e)
console.trace()
message.error(t('msg.error.formValidationFailed'))
const errorMsgs = e.errorFields
?.map((e: any) => e.errors?.join(', '))
.filter(Boolean)
.join(', ')
if (errorMsgs) {
message.error(errorMsgs)
} else {
message.error(t('msg.error.formValidationFailed'))
}
return
}

4
packages/nc-gui/package-lock.json generated

@ -11738,7 +11738,7 @@
}
},
"node_modules/nocodb-sdk": {
"version": "0.98.4",
"version": "0.99.0",
"resolved": "file:../nocodb-sdk",
"license": "AGPL-3.0-or-later",
"dependencies": {
@ -26029,7 +26029,7 @@
}
},
"nocodb-sdk": {
"version": "0.98.4",
"version": "0.99.0",
"requires": {
"axios": "^0.21.1",
"jsep": "^1.3.6"

1
packages/nc-gui/pages/account/index.vue

@ -68,6 +68,7 @@ const openKeys = ref([/^\/account\/users/.test($route.fullPath) && 'users'])
</div>
</a-menu-item>
<a-menu-item
v-if="isUIAllowed('appStore')"
key="apps"
class="group active:(!ring-0) hover:(!bg-primary !bg-opacity-25)"
@click="navigateTo('/account/apps')"

2
packages/nc-lib-gui/package.json

@ -1,6 +1,6 @@
{
"name": "nc-lib-gui",
"version": "0.98.4",
"version": "0.99.0",
"description": "NocoDB GUI",
"author": {
"name": "NocoDB",

15
packages/noco-docs/content/en/engineering/development-setup.md

@ -1,9 +1,9 @@
---
title: "Development setup"
title: "Development Setup"
description: "How to set-up your development environment"
position: 3200
category: "Engineering"
menuTitle: "Development setup"
menuTitle: "Development Setup"
---
## Clone the repo
@ -13,6 +13,7 @@ cd nocodb/packages
```
## Build SDK
```
# build nocodb-sdk
cd nocodb-sdk
@ -21,6 +22,7 @@ npm run build
```
## Build Backend
```
# build backend - runs on port 8080
cd ../nocodb
@ -29,6 +31,7 @@ npm run watch:run
```
## Build Frontend
```
# build frontend - runs on port 3000
cd ../nc-gui
@ -38,11 +41,13 @@ npm run dev
Any changes made to frontend and backend will be automatically reflected in the browser.
## Enabling CI-CD for draft PR
## Enabling CI-CD for Draft PR
CI-CD will be triggered on moving a PR from draft state to `Ready for review` state & on pushing changes to `Develop`. To verify CI-CD before requesting for review, add label `trigger-CI` on Draft PR.
## Accessing CI-CD failure screenshots
For Cypress tests, screenshots are captured on test failure. These will provide vital clues for debugging possible issues observed in CI-CD. To access screenshots, Open link associated with CI-CD run & click on `Artifacts`
## Accessing CI-CD Failure Screenshots
For Playwright tests, screenshots are captured on the tests. These will provide vital clues for debugging possible issues observed in CI-CD. To access screenshots, Open link associated with CI-CD run & click on `Artifacts`
![Screenshot 2022-09-29 at 12 43 37 PM](https://user-images.githubusercontent.com/86527202/192965070-dc04b952-70fb-4197-b4bd-ca7eda066e60.png)

4
packages/noco-docs/content/en/engineering/repository-structure.md

@ -1,9 +1,9 @@
---
title: "Repository structure"
description: "Repository structure"
description: "Repository Structure"
position: 3100
category: "Engineering"
menuTitle: "Repository structure"
menuTitle: "Repository Structure"
---
We use ``Lerna`` to manage multi-packages. We have the following [packages](https://github.com/nocodb/nocodb/tree/master/packages).

3
packages/noco-docs/content/en/engineering/testing.md

@ -3,7 +3,7 @@ title: "Writing Tests"
description: "Overview to testing"
position: 3250
category: "Engineering"
menuTitle: "Testing"
menuTitle: "Writing Tests"
---
## Unit Tests
@ -36,6 +36,7 @@ Configure the following variables
> DB_PASSWORD : password </br>
### Run Tests
``` bash
npm run test:unit
```

48
packages/noco-docs/content/en/setup-and-usages/account-settings.md

@ -0,0 +1,48 @@
---
title: 'Account Settings'
description: 'NocoDB provides Account Settings for managing your account or more for super admin'
position: 800
category: 'Product'
menuTitle: 'Account Settings'
---
## Overview
Account Settings allow you to manage your account such as your password or tokens.
![image](https://user-images.githubusercontent.com/35857179/203260408-7767daec-a862-4b33-8a6a-6706bff01eb7.png)
## Reset Password
<img width="1500" alt="image" src="https://user-images.githubusercontent.com/35857179/203267251-139fff32-38a9-4f39-af4f-c2c6ec5456bb.png">
## Token Management
- Newly created tokens are associated with the created user and it will have all permissions that particular user has.
- Existing token will work as it is and only be visible to the super admin.
<img width="1506" alt="image" src="https://user-images.githubusercontent.com/35857179/203267432-352d3038-7784-4ea5-b521-1d0252ffbf70.png">
If you are a super admin, you can also manage all user roles in organization level.
## User Management
Super-admin has new privelege to do user management at root-level.
- `org-level-creator` - this user can create a new project and access any invited project.
- `org-level-viewer` - this user can't create a new project but they can access any invited project.
![image](https://user-images.githubusercontent.com/35857179/203261168-5ba75f9c-476e-4fe7-ace4-f81051f42773.png)
## Enable / Disable Signup
Signup without an invitation is disabled by default and can be managed from UI by a super admin.
![image](https://user-images.githubusercontent.com/35857179/203268555-a17fcd39-5fb9-448d-aeaf-e55cbf49f6c5.png)
## App Store
You can also manage the app store plugins here.
![image](https://user-images.githubusercontent.com/35857179/203267619-24a8f5f5-1c8c-4419-a7a1-be4377fe6216.png)

13
packages/noco-docs/content/en/setup-and-usages/app-store.md

@ -1,17 +1,22 @@
---
title: 'App Store'
title: 'Team & Settings > App Store'
description: 'NocoDB provides different integrations in three main categories in App Store'
position: 1100
position: 590
category: 'Product'
menuTitle: 'App Store'
menuTitle: 'Team & Settings > App Store'
---
## Overview
To access it, click the down arrow button next to Project Name on the top left side, then select `Team & Settings` and clicking `App Store`.
<img width="322" alt="image" src="https://user-images.githubusercontent.com/35857179/194856648-67936db0-ee4d-4060-be3d-af9f86ef8fc6.png"> | <img width="471" alt="image" src="https://user-images.githubusercontent.com/35857179/203266301-064a6706-828b-457c-ab7b-868ba66d67e6.png">
|--|--|
We provide different integrations in three main categories.
| Category | App Name |
|---|---|
| Chat | Microsoft Teams <br/> Discord <br/> Twilio <br/> Whatsapp Twilio<br/> Mattermost<br/> Slack |
| Email | SMTP<br/> MailerSend<br/> AWS SES |
| Storage | AWS S3 <br/> Minio <br/> Google Cloud Storage <br/> Spaces <br/> Backblaze B2 <br/> Vultr Object Storage <br/> OvhCloud Object Storage <br/> Linode Object Storage <br/> UpCloud Object Storage <br/> Scaleway Object Storage |
| Storage | AWS S3 <br/> Minio <br/> Google Cloud Storage <br/> Spaces <br/> Backblaze B2 <br/> Vultr Object Storage <br/> OvhCloud Object Storage <br/> Linode Object Storage <br/> UpCloud Object Storage <br/> Scaleway Object Storage |

8
packages/noco-docs/content/en/setup-and-usages/audit.md

@ -1,11 +1,13 @@
---
title: 'Audit'
title: 'Team & Settings > Audit'
description: 'NocoDB provides all the user operation logs under Audit log'
position: 590
position: 610
category: 'Product'
menuTitle: 'Audit'
menuTitle: 'Team & Settings > Audit'
---
## Overview
We are keeping all the user operation logs under Audit. To access it, click the down arrow button next to Project Name on the top left side, then select `Team & Settings`.
<img width="322" alt="image" src="https://user-images.githubusercontent.com/35857179/194856648-67936db0-ee4d-4060-be3d-af9f86ef8fc6.png">

39
packages/noco-docs/content/en/setup-and-usages/expanded-form.md

@ -0,0 +1,39 @@
---
title: 'Expanded Form'
description: 'NocoDB provides Expanded Form to let you edit your data easily'
position: 1000
category: 'Product'
menuTitle: 'Expanded Form'
---
## Overview
Expanded Form allows you to edit a row data in a form. It also shows the activity feed such as user comments or revision history. It can be also shared by others by copying the record URL.
![image](https://user-images.githubusercontent.com/35857179/203273340-987b1242-9c78-4195-9ca2-3d3c49c7bccf.png)
## Expanding a Record
In a grid view, we can hover a row record and a doulbe arrow will be shown. By clicking it, the expanded form will be opened.
![image](https://user-images.githubusercontent.com/35857179/203274054-d20dc12b-7da8-4e6b-a144-19859b3c1c9c.png)
Alternatively, we can highlight a cell and press the space bar. The expanded form for the correpsonding row will be opened.
## Activity Feed
In an expanded form, we can click `Toggle Comment View` button to show the activity feed where we can optionally filter out comments only.
![image](https://user-images.githubusercontent.com/35857179/203275800-c8bc93f1-2a99-4766-8b81-70208c5675ca.png)
## Copy Record URL
In an expanded form, we can click `Copy Record URL` to share the record form to other authorized users.
![image](https://user-images.githubusercontent.com/35857179/203276149-bc97c70a-8bbf-48b4-a3fb-dd437c9405d3.png)
## Save Button Option
By default, when we save the form, the expanded form will be closed, i.e. `Save & Exit`. However, if we prefer not to close the form even after saving, we can choose `Save & Stay` mode instead. This is useful when you are editing a long form and you want to save it from time to time.
![image](https://user-images.githubusercontent.com/35857179/203276349-5d5c68d6-4523-41ae-8e23-312d2f6e9caa.png)

4
packages/noco-docs/content/en/setup-and-usages/meta-management.md

@ -1,9 +1,9 @@
---
title: 'Metadata'
title: 'Team & Settings > Project Metadata'
description: 'NocoDB Project Metadata'
position: 600
category: 'Product'
menuTitle: 'Metadata'
menuTitle: 'Team & Settings > Project Metadata'
---
Project Metadata includes Database Metadata, UI Access Control and Miscellaneous.

9
packages/noco-docs/content/en/setup-and-usages/table-operations.md

@ -116,17 +116,24 @@ For adding new values to the table we need new rows, new rows can be added in tw
- A new empty row will be created
<img width="567" alt="image" src="https://user-images.githubusercontent.com/35857179/189080009-3aeb70b4-92b0-4702-acb9-e5e52e31855e.png">
### Row Add (Pressing Enter Key from Previous Row)
When you finish editing a cell and press Enter, the cell in the next row with the same column will be highlighted.
![image](https://user-images.githubusercontent.com/35857179/203271676-bab64ca4-e0e4-4deb-9a62-609a97158911.png)
### Row Edit
You can start editing by any of the following methods
- Double click on cell to edit
- Click on cell and start typing (this way it will clear the previous content)
- Click on cell and press enter to start editing
- Click on cell and press enter to start editing
- And it will automatically save on blur event or if inactive.
### Row Delete
Right-click on anywhere in the row and then from the context menu select `Delete Row` option.
Bulk delete is also possible by selecting multiple rows by using the checkbox in first column and then `Delete Selected Rows` options from the right click context menu.
<img width="568" alt="image" src="https://user-images.githubusercontent.com/35857179/189081764-9f13c286-e02a-40d0-93ea-4b1362d96827.png">

7
packages/noco-docs/content/en/setup-and-usages/team-and-auth.md

@ -1,12 +1,13 @@
---
title: 'Team & Auth'
title: 'Team & Settings > Team & Auth'
description: 'Breakdown of roles & permissions for team user management'
position: 630
position: 580
category: 'Product'
menuTitle: 'Team & Auth'
menuTitle: 'Team & Settings > Team & Auth'
---
# Accessing Team & Auth
- Click on `Team & Settings` from the `Project Menu`
- Access `Team & Auth` under `Settings`

2
packages/noco-docs/content/en/setup-and-usages/views.md

@ -1,7 +1,7 @@
---
title: 'Views'
description: 'Understanding Views in NocoDB!'
position: 600
position: 700
category: 'Product'
menuTitle: 'Views'
---

4
packages/nocodb-sdk/package-lock.json generated

@ -1,12 +1,12 @@
{
"name": "nocodb-sdk",
"version": "0.98.4",
"version": "0.99.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "nocodb-sdk",
"version": "0.98.4",
"version": "0.99.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
"axios": "^0.21.1",

2
packages/nocodb-sdk/package.json

@ -1,6 +1,6 @@
{
"name": "nocodb-sdk",
"version": "0.98.4",
"version": "0.99.0",
"description": "NocoDB SDK",
"main": "build/main/index.js",
"typings": "build/main/index.d.ts",

34
packages/nocodb/package-lock.json generated

@ -1,12 +1,12 @@
{
"name": "nocodb",
"version": "0.98.4",
"version": "0.99.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "nocodb",
"version": "0.98.4",
"version": "0.99.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@google-cloud/storage": "^5.7.2",
@ -64,7 +64,7 @@
"mysql2": "^2.2.5",
"nanoid": "^3.1.20",
"nc-help": "0.2.79",
"nc-lib-gui": "0.98.4",
"nc-lib-gui": "0.99.0",
"nc-plugin": "0.1.2",
"ncp": "^2.0.0",
"nocodb-sdk": "file:../nocodb-sdk",
@ -4804,9 +4804,9 @@
}
},
"node_modules/engine.io": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz",
"integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz",
"integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==",
"dependencies": {
"@types/cookie": "^0.4.1",
"@types/cors": "^2.8.12",
@ -10610,9 +10610,9 @@
}
},
"node_modules/nc-lib-gui": {
"version": "0.98.4",
"resolved": "https://registry.npmjs.org/nc-lib-gui/-/nc-lib-gui-0.98.4.tgz",
"integrity": "sha512-6E8NCOm8nRbJ+9WIE+5YOFas6OIINj95X0wVKVScMGSpPZ9xIHXLKXZYjIoqEFT2Q94wAV8vPPX2iZhvqXDeZw==",
"version": "0.99.0",
"resolved": "https://registry.npmjs.org/nc-lib-gui/-/nc-lib-gui-0.99.0.tgz",
"integrity": "sha512-3wSn6FVTffbPHpV0OWJeaHJ4q9/1y3QM5ltVNf5sIjunN9HEBstvf+EjJ5UGQIad6/CYKGR5DnIi0uUux/ymOA==",
"dependencies": {
"express": "^4.17.1"
}
@ -10663,7 +10663,7 @@
"dev": true
},
"node_modules/nocodb-sdk": {
"version": "0.98.4",
"version": "0.99.0",
"resolved": "file:../nocodb-sdk",
"license": "AGPL-3.0-or-later",
"dependencies": {
@ -21566,9 +21566,9 @@
}
},
"engine.io": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz",
"integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz",
"integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==",
"requires": {
"@types/cookie": "^0.4.1",
"@types/cors": "^2.8.12",
@ -26047,9 +26047,9 @@
}
},
"nc-lib-gui": {
"version": "0.98.4",
"resolved": "https://registry.npmjs.org/nc-lib-gui/-/nc-lib-gui-0.98.4.tgz",
"integrity": "sha512-6E8NCOm8nRbJ+9WIE+5YOFas6OIINj95X0wVKVScMGSpPZ9xIHXLKXZYjIoqEFT2Q94wAV8vPPX2iZhvqXDeZw==",
"version": "0.99.0",
"resolved": "https://registry.npmjs.org/nc-lib-gui/-/nc-lib-gui-0.99.0.tgz",
"integrity": "sha512-3wSn6FVTffbPHpV0OWJeaHJ4q9/1y3QM5ltVNf5sIjunN9HEBstvf+EjJ5UGQIad6/CYKGR5DnIi0uUux/ymOA==",
"requires": {
"express": "^4.17.1"
}
@ -26091,7 +26091,7 @@
"dev": true
},
"nocodb-sdk": {
"version": "0.98.4",
"version": "0.99.0",
"requires": {
"axios": "^0.21.1",
"jsep": "^1.3.6"

4
packages/nocodb/package.json

@ -1,6 +1,6 @@
{
"name": "nocodb",
"version": "0.98.4",
"version": "0.99.0",
"description": "NocoDB Backend",
"main": "dist/bundle.js",
"author": {
@ -107,7 +107,7 @@
"mysql2": "^2.2.5",
"nanoid": "^3.1.20",
"nc-help": "0.2.79",
"nc-lib-gui": "0.98.4",
"nc-lib-gui": "0.99.0",
"nc-plugin": "0.1.2",
"ncp": "^2.0.0",
"nocodb-sdk": "file:../nocodb-sdk",

2
packages/nocodb/src/lib/db/sql-client/lib/KnexClient.ts

@ -892,7 +892,7 @@ class KnexClient extends SqlClient {
getMinMax(_columnObject) {}
async mockDb(_args) {
// todo: remove method
// todo: remove method
}
async dbCacheInitAsyncKnex(_cbk = null) {

83
packages/nocodb/src/lib/db/sql-client/lib/mssql/MssqlClient.ts

@ -356,12 +356,14 @@ class MssqlClient extends KnexClient {
try {
/** ************** START : create _evolution table if not exists *************** */
const exists = await this.sqlClient.schema.withSchema(this.schema).hasTable(args.tn);
const exists = await this.sqlClient.schema
.withSchema(this.schema)
.hasTable(args.tn);
if (!exists) {
await this.sqlClient.schema.withSchema(this.schema).createTable(
args.tn,
function (table) {
await this.sqlClient.schema
.withSchema(this.schema)
.createTable(args.tn, function (table) {
table.increments();
table.string('title').notNullable();
table.string('titleDown').nullable();
@ -371,8 +373,7 @@ class MssqlClient extends KnexClient {
table.integer('status').nullable();
table.dateTime('created');
table.timestamps();
}
);
});
log.debug('Table created:', `${this.getTnPath(args.tn)}`);
} else {
log.debug(`${this.getTnPath(args.tn)} tables exists`);
@ -394,7 +395,9 @@ class MssqlClient extends KnexClient {
log.api(`${_func}:args:`, args);
try {
result.data.value = await this.sqlClient.schema.withSchema(this.schema).hasTable(args.tn);
result.data.value = await this.sqlClient.schema
.withSchema(this.schema)
.hasTable(args.tn);
} catch (e) {
log.ppe(e, _func);
throw e;
@ -1814,7 +1817,10 @@ class MssqlClient extends KnexClient {
const downStatement =
this.querySeparator() +
this.sqlClient.schema.withSchema(this.schema).dropTable(args.table).toString();
this.sqlClient.schema
.withSchema(this.schema)
.dropTable(args.table)
.toString();
this.emit(`Success : ${upQuery}`);
@ -1856,7 +1862,15 @@ class MssqlClient extends KnexClient {
BEGIN
SET NOCOUNT ON;
UPDATE ?? Set ?? = GetDate() where ?? in (SELECT ?? FROM Inserted)
END;`, [triggerName, this.getTnPath(args.table_name), this.getTnPath(args.table_name), column.column_name, pk.column_name, pk.column_name]
END;`,
[
triggerName,
this.getTnPath(args.table_name),
this.getTnPath(args.table_name),
column.column_name,
pk.column_name,
pk.column_name,
]
);
upQuery += triggerCreateQuery;
@ -2058,7 +2072,10 @@ class MssqlClient extends KnexClient {
/** ************** create up & down statements *************** */
const upStatement =
this.querySeparator() +
this.sqlClient.schema.withSchema(this.schema).dropTable(args.tn).toString();
this.sqlClient.schema
.withSchema(this.schema)
.dropTable(args.tn)
.toString();
let downQuery = this.querySeparator() + this.createTable(args.tn, args);
this.emit(`Success : ${upStatement}`);
@ -2072,8 +2089,9 @@ class MssqlClient extends KnexClient {
for (const relation of relationsList) {
downQuery +=
this.querySeparator() +
(await this.sqlClient.withSchema(this.schema).schema
.table(relation.tn, (table) => {
(await this.sqlClient
.withSchema(this.schema)
.schema.table(relation.tn, (table) => {
table = table
.foreign(relation.cn, null)
.references(relation.rcn)
@ -2116,7 +2134,8 @@ class MssqlClient extends KnexClient {
)) {
downQuery +=
this.querySeparator() +
this.sqlClient.schema.withSchema(this.schema)
this.sqlClient.schema
.withSchema(this.schema)
.table(tn, function (table) {
if (non_unique) {
table.index(columns, key_name);
@ -2152,7 +2171,7 @@ class MssqlClient extends KnexClient {
* @param {String} - args.childTable
* @returns {Promise<{upStatement, downStatement}>}
*/
async relationCreate(args) {
async relationCreate(args) {
const _func = this.relationCreate.name;
const result = new Result();
log.api(`${_func}:args:`, args);
@ -2161,19 +2180,22 @@ class MssqlClient extends KnexClient {
try {
const self = this;
await this.sqlClient.schema.table(this.getTnPath(args.childTable), function (table) {
table = table
.foreign(args.childColumn, foreignKeyName)
.references(args.parentColumn)
.on(self.getTnPath(args.parentTable));
if (args.onUpdate) {
table = table.onUpdate(args.onUpdate);
}
if (args.onDelete) {
table = table.onDelete(args.onDelete);
await this.sqlClient.schema.table(
this.getTnPath(args.childTable),
function (table) {
table = table
.foreign(args.childColumn, foreignKeyName)
.references(args.parentColumn)
.on(self.getTnPath(args.parentTable));
if (args.onUpdate) {
table = table.onUpdate(args.onUpdate);
}
if (args.onDelete) {
table = table.onDelete(args.onDelete);
}
}
});
);
const upStatement =
this.querySeparator() +
@ -2234,9 +2256,12 @@ class MssqlClient extends KnexClient {
try {
const self = this;
await this.sqlClient.schema.table(this.getTnPath(args.childTable), function (table) {
table.dropForeign(args.childColumn, foreignKeyName);
});
await this.sqlClient.schema.table(
this.getTnPath(args.childTable),
function (table) {
table.dropForeign(args.childColumn, foreignKeyName);
}
);
const upStatement =
this.querySeparator() +

4
packages/nocodb/src/lib/db/sql-client/lib/pg/PgClient.ts

@ -468,7 +468,9 @@ class PGClient extends KnexClient {
}
if (rows.length === 0) {
log.debug('creating database:', args);
await tempSqlClient.raw(`CREATE DATABASE ?? ENCODING 'UTF8'`, [args.database]);
await tempSqlClient.raw(`CREATE DATABASE ?? ENCODING 'UTF8'`, [
args.database,
]);
}
// if (this.connectionConfig.searchPath && this.connectionConfig.searchPath[0]) {

26
packages/nocodb/src/lib/db/sql-data-mapper/lib/BaseModel.ts

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/ban-types,prefer-const */
import { Knex } from 'knex';
import { Knex } from 'knex';
import Filter from '../../../models/Filter';
import Sort from '../../../models/Sort';
@ -220,10 +220,7 @@ abstract class BaseModel {
const query = this.$db.insert(data);
if (
this.dbDriver.client === 'pg' ||
this.dbDriver.client === 'mssql'
) {
if (this.dbDriver.client === 'pg' || this.dbDriver.client === 'mssql') {
query.returning('*');
response = await this._run(query);
} else {
@ -265,10 +262,7 @@ abstract class BaseModel {
const query = this.$db.insert(data);
if (
this.dbDriver.client === 'pg' ||
this.dbDriver.client === 'mssql'
) {
if (this.dbDriver.client === 'pg' || this.dbDriver.client === 'mssql') {
query.returning('*');
response = await this._run(query);
} else {
@ -302,13 +296,13 @@ abstract class BaseModel {
for (const d of data) {
await this.validate(d);
}
const response = (this.dbDriver.client === 'pg' || this.dbDriver.client === 'mssql') ?
this.dbDriver
.batchInsert(this.tn, data, 50)
.returning(this.pks?.[0]?.cn || '*') :
this.dbDriver
.batchInsert(this.tn, data, 50);
const response =
this.dbDriver.client === 'pg' || this.dbDriver.client === 'mssql'
? this.dbDriver
.batchInsert(this.tn, data, 50)
.returning(this.pks?.[0]?.cn || '*')
: this.dbDriver.batchInsert(this.tn, data, 50);
await this.afterInsertb(data);

17
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSql.ts

@ -417,10 +417,7 @@ class BaseModelSql extends BaseModel {
const query = dbDriver(this.tnPath).insert(insertObj);
if (
this.dbDriver.client === 'pg' ||
this.dbDriver.client === 'mssql'
) {
if (this.dbDriver.client === 'pg' || this.dbDriver.client === 'mssql') {
query.returning(this.selectQuery(''));
response = await this._run(query);
}
@ -608,12 +605,12 @@ class BaseModelSql extends BaseModel {
await this.validate(d1);
}
const response = (this.dbDriver.client === 'pg' || this.dbDriver.client === 'mssql') ?
await this.dbDriver
.batchInsert(this.tn, insertDatas, 50)
.returning(this.pks[0].cn) :
await this.dbDriver
.batchInsert(this.tn, insertDatas, 50);
const response =
this.dbDriver.client === 'pg' || this.dbDriver.client === 'mssql'
? await this.dbDriver
.batchInsert(this.tn, insertDatas, 50)
.returning(this.pks[0].cn)
: await this.dbDriver.batchInsert(this.tn, insertDatas, 50);
await this.afterInsertb(insertDatas, null);

3
packages/nocodb/src/lib/meta/api/dataApis/dataAliasApis.ts

@ -270,7 +270,8 @@ async function getGroupedDataList(model, view: View, req) {
data = data.map((item) => {
// todo: use map to avoid loop
const count =
countArr.find((countItem: any) => countItem.key === item.key)?.count ?? 0;
countArr.find((countItem: any) => countItem.key === item.key)?.count ??
0;
item.value = new PagedResponseImpl(item.value, {
...req.query,

4
packages/nocodb/src/lib/meta/api/index.ts

@ -1,5 +1,5 @@
import { Tele } from 'nc-help';
import orgLicenseApis from './orgLicenseApis'
import orgLicenseApis from './orgLicenseApis';
import orgTokenApis from './orgTokenApis';
import orgUserApis from './orgUserApis';
import projectApis from './projectApis';
@ -61,7 +61,7 @@ export default function (router: Router, server) {
projectApis(router);
utilApis(router);
if(process.env['PLAYWRIGHT_TEST'] === 'true') {
if (process.env['PLAYWRIGHT_TEST'] === 'true') {
router.use(testApis);
}
router.use(columnApis);

4
packages/nocodb/src/lib/meta/api/orgLicenseApis.ts

@ -1,12 +1,10 @@
import { Router } from 'express';
import { OrgUserRoles } from 'nocodb-sdk';
import { NC_LICENSE_KEY } from '../../constants'
import { NC_LICENSE_KEY } from '../../constants';
import Store from '../../models/Store';
import { metaApiMetrics } from '../helpers/apiMetrics';
import ncMetaAclMw from '../helpers/ncMetaAclMw';
async function licenseGet(_req, res) {
const license = await Store.get(NC_LICENSE_KEY);

3
packages/nocodb/src/lib/meta/api/publicApis/publicDataApis.ts

@ -157,7 +157,8 @@ async function getGroupedDataList(model, view: View, req) {
data = data.map((item) => {
// todo: use map to avoid loop
const count =
countArr.find((countItem: any) => countItem.key === item.key)?.count ?? 0;
countArr.find((countItem: any) => countItem.key === item.key)?.count ??
0;
item.value = new PagedResponseImpl(item.value, {
...req.query,

2
packages/nocodb/src/lib/meta/api/swagger/swaggerApis.ts

@ -2,7 +2,7 @@
import catchError, { NcError } from '../../helpers/catchError';
import { Router } from 'express';
import Model from '../../../models/Model';
import ncMetaAclMw from '../../helpers/ncMetaAclMw'
import ncMetaAclMw from '../../helpers/ncMetaAclMw';
import getSwaggerJSON from './helpers/getSwaggerJSON';
import Project from '../../../models/Project';
import swaggerHtml from './swaggerHtml';

12
packages/nocodb/src/lib/meta/api/sync/helpers/job.ts

@ -2237,9 +2237,12 @@ export default async (
for (let i = 0; i < ncTblList.list.length; i++) {
// not a migrated table, skip
if (undefined === aTblSchema.find((x) => x.name === ncTblList.list[i].title))
if (
undefined ===
aTblSchema.find((x) => x.name === ncTblList.list[i].title)
)
continue;
const _perfStart = recordPerfStart();
const ncTbl = await api.dbTable.read(ncTblList.list[i].id);
recordPerfStats(_perfStart, 'dbTable.read');
@ -2265,7 +2268,10 @@ export default async (
logBasic('Configuring Record Links...');
for (let i = 0; i < ncTblList.list.length; i++) {
// not a migrated table, skip
if (undefined === aTblSchema.find((x) => x.name === ncTblList.list[i].title))
if (
undefined ===
aTblSchema.find((x) => x.name === ncTblList.list[i].title)
)
continue;
const ncTbl = await api.dbTable.read(ncTblList.list[i].id);

2
packages/nocodb/src/lib/meta/api/testApis.ts

@ -6,7 +6,7 @@ export async function reset(req: Request<any, any>, res) {
parallelId: req.body.parallelId,
dbType: req.body.dbType,
isEmptyProject: req.body.isEmptyProject,
workerId: req.body.workerId
workerId: req.body.workerId,
});
res.json(await service.process());

18
packages/nocodb/src/lib/services/test/TestResetService/index.ts

@ -23,7 +23,7 @@ const loginRootUser = async () => {
const projectTitleByType = {
sqlite: 'sampleREST',
mysql: 'externalREST',
pg: 'pgExtREST'
pg: 'pgExtREST',
};
export class TestResetService {
@ -37,7 +37,7 @@ export class TestResetService {
parallelId,
dbType,
isEmptyProject,
workerId
workerId,
}: {
parallelId: string;
dbType: string;
@ -73,7 +73,7 @@ export class TestResetService {
token,
dbType: this.dbType,
parallelId: this.parallelId,
workerId: this.workerId
workerId: this.workerId,
});
try {
@ -96,7 +96,7 @@ export class TestResetService {
token,
dbType,
parallelId,
workerId
workerId,
}: {
token: string;
dbType: string;
@ -123,7 +123,7 @@ export class TestResetService {
token,
title,
parallelId,
isEmptyProject: this.isEmptyProject
isEmptyProject: this.isEmptyProject,
});
} else if (dbType == 'mysql') {
await resetMysqlSakilaProject({
@ -131,7 +131,7 @@ export class TestResetService {
title,
parallelId,
oldProject: project,
isEmptyProject: this.isEmptyProject
isEmptyProject: this.isEmptyProject,
});
} else if (dbType == 'pg') {
await resetPgSakilaProject({
@ -139,12 +139,12 @@ export class TestResetService {
title,
parallelId: workerId,
oldProject: project,
isEmptyProject: this.isEmptyProject
isEmptyProject: this.isEmptyProject,
});
}
return {
project: await Project.getByTitle(title)
project: await Project.getByTitle(title),
};
}
}
@ -177,7 +177,7 @@ const removeProjectUsersFromCache = async (project: Project) => {
const projectUsers: ProjectUser[] = await ProjectUser.getUsersList({
project_id: project.id,
limit: 1000,
offset: 0
offset: 0,
});
for (const projectUser of projectUsers) {

10
packages/nocodb/src/lib/utils/projectAcl.ts

@ -157,7 +157,7 @@ export default {
dataCount: true,
upload: true,
uploadViaURL: true,
swaggerJson:true
swaggerJson: true,
},
},
commenter: {
@ -217,7 +217,7 @@ export default {
xcAuditModelCommentsCount: true,
xcExportAsCsv: true,
dataCount: true,
swaggerJson:true
swaggerJson: true,
},
},
viewer: {
@ -273,7 +273,7 @@ export default {
list: true,
xcExportAsCsv: true,
dataCount: true,
swaggerJson:true
swaggerJson: true,
},
},
[OrgUserRoles.VIEWER]: {
@ -294,11 +294,7 @@ export default {
upload: true,
uploadViaURL: true,
passwordChange: true,
pluginList: true,
pluginRead: true,
pluginTest: true,
isPluginActive: true,
pluginUpdate: true,
projectCreate: true,
projectList: true,
projectCost: true,

Loading…
Cancel
Save